Machine Learning - 第6周(Advice for Applying Machine Learning、Machine Learning System Design)
In Week 6, you will be learning about systematically improving your learning algorithm. The videos for this week will teach you how to tell when a learning algorithm is doing poorly, and describe the 'best practices' for how to 'debug' your learning algorithm and go about improving its performance.
We will also be covering machine learning system design. To optimize a machine learning algorithm, you’ll need to first understand where the biggest improvements can be made. In these lessons, we discuss how to understand the performance of a machine learning system with multiple parts, and also how to deal with skewed data.
When you're applying machine learning to real problems, a solid grasp of this week's content will easily save you a large amount of work.
Advice for Applying Machine Learning
Evaluating a Learning Algorithm
Deciding What to Try Next
到目前为止 我们已经介绍了许多不同的学习算法 如果你一直跟着这些视频的进度学习 你会发现自己已经不知不觉地 成为一个了解许多先进机器学习技术的专家了 然而 在懂机器学习的人当中 依然存在着很大的差距 一部分人确实掌握了 怎样高效有力地 运用这些学习算法 而另一些人 他们可能对我马上要讲的东西 就不是那么熟悉了 他们可能没有完全理解 怎样运用这些算法 因此总是 把时间浪费在 毫无意义的尝试上 我想做的是 确保你在设计 机器学习的系统时 你能够明白怎样选择 一条最合适 最正确的道路 因此 在这节视频 和之后的几段视频中 我将向你介绍一些实用的 建议和指导 帮助你明白怎样进行选择 具体来讲 我将重点关注的问题是 假如你在开发 一个机器学习系统 或者想试着改进 一个机器学习系统的性能 你应如何决定 接下来应该 选择哪条道路? 为了解释这一问题 我想仍然使用 预测房价的学习例子 假如你已经完成了正则化线性回归 也就是最小化代价函数J的值 假如 在你得到你的学习参数以后 如果你要将你的假设函数 放到一组新的房屋样本上进行测试 假如说你发现在预测房价时 产生了巨大的误差 现在你的问题是 要想改进这个算法 接下来应该怎么办? 实际上你可以想出 很多种方法来改进 这个算法的性能 其中一种办法是 使用更多的训练样本 具体来讲 也许你能想到 通过电话调查 或上门调查 来获取更多的 不同的房屋出售数据 遗憾的是 我看到好多人花费了好多时间 想收集更多的训练样本 他们总认为 噢 要是我有 两倍甚至十倍数量的训练数据 那就一定会解决问题的 是吧? 但有时候 获得更多的训练数据 实际上并没有作用 在接下来的几段视频中 我们将解释原因 我们也将知道 怎样避免把过多的时间 浪费在收集更多的训练数据上 这实际上是于事无补的 另一个方法 你也许能想到的 是尝试选用更少的特征集 因此如果你有一系列特征 比如x1 x2 x3等等 也许有很多特征 也许你可以花一点时间 从这些特征中 仔细挑选一小部分来防止过拟合 或者也许你需要用更多的特征 也许目前的特征集 对你来讲并不是很有帮助 你希望从获取更多特征的角度 来收集更多的数据 同样地 你可以把这个问题 扩展为一个很大的项目 比如使用电话调查 来获得更多有关 或者再进行土地测量 来获得更多有关 这块土地的信息等等 因此这是一个复杂的问题 同样的道理 我们非常希望 在花费大量时间完成这些工作之前 我们就能知道其效果如何 我们也可以尝试 增加多项式特征的方法 比如x1的平方 x2的平方 x1 x2的乘积 我们可以花很多时间 来考虑这一方法 我们也可以考虑其他方法 减小或增大正则化参数lambda的值 我们列出的这个单子 上面的很多方法 都可以扩展开来 扩展成一个六个月或更长时间的项目 遗憾的是 大多数人用来选择这些方法的标准 是凭感觉的 也就是说 大多数人的选择方法是 随便从这些方法中选择一种 比如他们会说 “噢 我们来多找点数据吧” 然后花上六个月的时间 收集了一大堆数据 然后也许另一个人说 “好吧 让我们来从这些房子的数据中多找点特征吧” 我很遗憾不止一次地看到 很多人花了 不夸张地说 至少六个月时间 来完成他们随便选择的一种方法 而在六个月或者更长时间后 他们很遗憾地发现 自己选择的是一条不归路 幸运的是 有一系列简单的方法 能让你事半功倍 排除掉单子上的 至少一半的方法 留下那些确实有前途的方法 同时也有一种很简单的方法 只要你使用 就能很轻松地排除掉很多选择 从而为你节省 大量不必要花费的时间 在接下来的两段视频中 我首先介绍 怎样评估机器学习算法的性能 然后在之后的几段视频中 我将开始 讨论这些方法 它们也被称为"机器学习诊断法" “诊断法”的意思是 这是一种测试法 你通过执行这种测试 能够深入了解 某种算法到底是否有用 这通常也能够告诉你 要想改进一种算法的效果 什么样的尝试 才是有意义的 在这一系列的视频中我们将介绍具体的诊断法 但我要提前说明一点的是 这些诊断法的执行和实现 是需要花些时间的 有时候 确实需要花很多时间 来理解和实现 但这样做的确是 更有效率地利用好你的时间 因为这些方法 让你在开发学习算法时 节省了几个月的时间 早点从不必要的尝试中解脱出来 早日脱离苦海 因此 在接下来几节课中 我将先来介绍 如何评价你的学习算法 在此之后 我将介绍一些诊断法 希望能让你更清楚 在接下来的尝试中 如何选择更有意义的方法 最终达到改进机器学习系统性能的目的
Evaluating a Hypothesis
在本节视频中我想介绍一下 怎样用你学过的算法来评估假设函数 在之后的课程中 我们将以此为基础来 讨论如何避免 过拟合和欠拟合的问题 当我们确定学习算法的参数的时候 我们考虑的是选择参量来使训练误差最小化 有人认为 得到一个非常小的训练误差 一定是一件好事 但我们已经知道 仅仅是因为这个假设具有很小的训练误差 并不能说明它就一定是一个好的假设函数 而且我们也学习了过拟合假设函数的例子 所以这推广到新的训练集上是不适用的 那么 你该如何判断一个假设函数是过拟合的呢 对于这个简单的例子 我们可以 对假设函数 h(x) 进行画图 然后观察图形趋势 但对于特征变量不止一个的这种一般情况 还有像有很多特征变量的问题 想要通过画出假设函数来进行观察 就会变得很难甚至是不可能实现 因此 我们需要另一种方法来评估我们的假设函数 如下给出了一种评估假设函数的标准方法 假设我们有这样一组数据组 在这里我只展示出10组训练样本 当然我们通常可以有 成百上千组训练样本 为了确保我们可以评估我们的假设函数 我们要做的是 将这些数据分成两部分 第一部分将成为我们的常用训练集 而第二部分将成为我们的测试集 将所有数据分成训练集和测试集 其中一种典型的分割方法是 按比例 将70%的数据作为训练集 30%的数据作为测试集 因此 现在如果我们有了一些数据 我们只用其中的70% 作为我们的训练集 这里的m依然表示训练样本的总数 而剩下的那部分数据 将被用作测试集 在这里 我使用m下标test 来表示测试样本的总数 因此 这里的下标test将表示 这些样本是来自测试集 因此x(1)test y(1)test将成为我的 第一组测试样本 我想应该是这里的这一组样本 最后再提醒一点 在这里我是选择了前70%的数据作为训练集 后30%的数据作为测试集 但如果这组数据有某种规律或顺序的话 那么最好是 随机选择70%作为训练集 剩下的30%作为测试集 当然如果你的数据已经随机分布了 那你可以选择前70%和后30% 但如果你的数据不是随机排列的 最好还是打乱顺序 或者使用一种随机的顺序来构建你的数据 然后再取出前70%作为训练集 后30%作为测试集 接下来 这里展示了一种典型的方法 你可以按照这些步骤训练和测试你的学习算法 比如线性回归算法 首先 你需要对训练集进行学习得到参数θ 具体来讲就是最小化训练误差J(θ) 这里的J(θ)是使用那70%数据 来定义得到的 也就是仅仅是训练数据 接下来 你要计算出测试误差 我将用J下标test来表示测试误差 那么你要做的就是 取出你之前从训练集中学习得到的参数θ放在这里 来计算你的测试误差 可以写成如下的形式 这实际上是测试集 平方误差的 平均值 这也不难想象 因此 我们使用包含参数θ的假设函数对每一个测试样本进行测试 然后通过假设函数和测试样本 计算出mtest个平方误差 当然 这是当我们使用线性回归 和平方误差标准时 测试误差的定义 那么如果是考虑分类问题 比如说使用逻辑回归的时候呢 训练和测试逻辑回归的步骤 与之前所说的非常类似 首先我们要从训练数据 也就是所有数据的70%中 学习得到参数θ 然后用如下的方式计算测试误差 目标函数和我们平常 做逻辑回归的一样 唯一的区别是 现在我们使用的是mtest个测试样本 这里的测试误差Jtest(θ) 其实不难理解 有时这是另一种形式的测试集 更易于理解 这里的误差其实叫误分类率 也被称为0/1错分率 0/1表示了 你预测到的正确或错误样本的情况 比如说 可以这样定义一次预测的误差 关于假设h(x) 和标签y的误差 那么这个误差等于1 当你的假设函数h(x)的值大于等于0.5 并且y的值等于0 或者当h(x)小于0.5 并且y的值等于1 因此 这两种情况都表明 你的假设对样本进行了误判 这里定义阈值为0.5 那么也就是说 假设结果更趋向于1 但实际是0 或者说假设更趋向于0 但实际的标签却是1 否则 我们将误差值定义为0 此时你的假设值能够正确对样本y进行分类 然后 我们就能应用错分率误差 来定义测试误差 也就是1/mtest 乘以 h(i)(xtest)和y(i)的错分率误差 从i=1到mtest 的求和 这样我就写出了我的定义方式 这实际上就是我的假设函数误标记的 那部分测试集中的样本 这也就是使用 0/1错分率或误分类率 的准则来定义的测试误差 以上我们介绍了一套标准技术 来评价一个已经学习过的假设 在下一段视频中我们要应用这些方法 来帮助我们进行诸如特征选择一类的问题 比如多项式次数的选择 或者正则化参数的选择
Model Selection and Train/Validation/Test Sets
假如你想要确定对于某组数据 最合适的多项式次数是几次 怎样选用正确的特征来构造学习算法 或者假如你需要正确选择 学习算法中的正则化参数λ 你应该怎样做呢? 这些问题我们称之为模型选择问题 在我们对于这一问题的讨论中 我们还将提到 如何将数据分为三组 也就是训练集、验证集和测试集 而不仅仅是前面提到的两组数据 在这节视频中 我们将会介绍这些内容的含义 以及如何使用它们进行模型选择 我们已经多次接触到过拟合现象 在过拟合的情况中 学习算法在适用于训练集时表现非常完美 但这并不代表此时的假设也很完美 更一般地说 这也是为什么训练集误差 通常不能正确预测出该假设是否能很好地拟合新样本的原因 具体来讲 如果你把这些参数集 比如θ0 θ1 θ2等等 调整到非常拟合你的训练集 那么结果就是 你的假设会在训练集上表现地很好 但这并不能确定 当你的假设推广到训练集之外的新的样本上时 预测的结果是怎样的 而更为普遍的规律是 只要你的参数非常拟合某个数据组 比如说 非常拟合训练集 当然也可以是其他数据集 那么你的假设对于相同数据组的预测误差 比如说训练误差 是不能够用来推广到一般情况的 或者说 是不能作为实际的泛化误差的 也就是说 不能说明你的假设对于新样本的效果 下面我们来考虑模型选择问题 假如说你现在要选择能最好地拟合你数据的多项式次数 换句话说 你应该选择一次函数 二次函数 还是三次函数呢 等等一直到十次函数 所以似乎应该有这样一个参数 这里我用 d 来表示 d表示的就是你应该选择的多项式次数 所以 似乎除了你要确定的参数θ之外 你还要考虑确定一个参数 你同样需要用你的数据组来确定这个多项式的次数d 第一个选择是 d=1 也就表示线性(一次)方程 我们也可以选择d=2或者3 等等一直到d=10 因此 我们想确定这个多出来的参数d最适当的取值 具体地说 比如你想要选择一个模型 那就从这10个模型中 选择一个最适当的多项式次数 并且用这个模型进行估计 预测你的假设能否很好地推广到新的样本上 那么你可以这样做 你可以先选择第一个模型 然后求训练误差的最小值 这样你就会得到 一个参数向量θ 然后你再选择第二个模型 二次函数模型 进行同样的过程 这样你会得到另一个参数向量 θ 为了区别这些不同的 参数向量θ 我想用上标(1) 上标(2)来表示 这里的上标(1)表示的是 在调整第一个模型 使其拟合训练数据时得到的参数θ 同样地 θ上标(2)表示的是 二次函数在和训练数据拟合的过程中得到的参数 以此类推 在拟合三次函数模型时我又得到一个参数θ(3) 等等 直到θ(10) 接下来我们要做的是 对所有这些模型 求出测试集误差 因此 我可以算出 Jtest(θ(1)) Jtest(θ(2)) Jtest(θ(3)) 以此类推 也就是对于每一个模型对应的假设 都计算出其作用于测试集的表现如何 接下来为了确定选择哪一个模型最好 我要做的是 看看这些模型中 哪一个对应的测试集误差最小 那么对于这一个例子 我们假设最终选择了五次多项式模型 目前看来还比较合理 那么现在 我确定了我的模型 我得到了我的假设 也就是这个五次函数模型 现在我想知道 这个模型能不能很好地推广到新样本 我们可以观察这个五次多项式假设模型 对测试集的拟合情况 但这里有一个问题是 这样做仍然不能公平地说明 我的假设推广到一般时的效果 其原因在于 我们刚才是使用的测试集 跟假设拟合 来得到的 多项式次数d 这个参数 这也就是说 我们选择了一个 能够最好地拟合测试集的 参数d的值 因此 我们的参数向量θ(5) 在拟合测试集时的结果 很可能导致一个比实际泛化误差更完美的预测结果 对吧? 因为我是找了一个最能拟合测试集的参数d 因此我再用测试集 来评价我的假设就显得不公平了 因为我已经选了一个能够最拟合测试集的参数 我选择的多项式次数d 本身就是按照最拟合测试集来选择的 因此我的假设 很可能很好地拟合测试集 而且这种拟合的效果很可能会比对那些没见过的新样本拟合得更好 而我们其实是更关心对新样本的拟合效果的 所以 再回过头来说 在前面的幻灯片中 我们看到 如果我们 用训练集来拟合参数 θ0 θ1 等等参数时 那么 拟合后的模型 在作用于训练集上的效果 是不能预测出 我们将这个假设推广到新样本上时效果如何的 这是因为这些参数能够很好地拟合训练集 因此它们很有可能 在对训练集的预测中表现地很好 但对其他的新样本来说 就不一定那么好了 而在刚才这一页幻灯片上 我讲到的步骤 也是在做同样的事 具体来讲 我们做的实际上是用测试集来拟合参数d 通过用测试集来拟合这个参数 同样也意味着 这并不能较为公平地预测出 假设函数的在遇到新样本时的表现 为了解决这一问题 在模型选择中 如果我们想要评价某个假设 我们通常采用以下的方法 给定某个数据集 和刚才将数据分为 训练和测试集不同的是 我们要将其分为三段 第一部分还是叫训练集 所以 我们还是称这部分为训练集 第二部分我把它叫做交叉验证集(cross validation set) Cross validation 我用CV来简写“交叉验证” 有时候也直接叫验证集 不叫交叉验证集 最后一部分依然和以前一样是测试集 同时 一种典型的分割比例是 将60%的数据 分给训练集 大约20%的数据给交叉验证集 最后20%给测试集 这个比例可以稍微调整 但这种分法是最典型的 所以现在我们的训练集就只占总数据的60%了 然后交叉验证集 或者说验证集 将拥有一部分样本 我把它的数量用m下标CV来表示 这是交叉验证集样本的数量 按照之前我们的符号表示习惯 我将用(x(i)CV, y(i)CV) 来表示第i个交叉验证样本 最后 我们还是有这样一些测试集样本 用m下标test来表示测试样本的总数 好的 现在我们就定义了训练集、交叉验证集 以及测试集 我们随之也可以定义训练误差 交叉验证误差 和测试误差 因此这便是我定义的训练误差 我用J下标train来表示 这跟我们之前定义的 J(θ)没有任何区别 也就是对训练集数据进行预测得到的误差 然后J下标CV定义为交叉验证集误差 这也不难想象 跟训练误差类似的定义 只不过是在交叉验证集上预测得到的误差 然后这是测试集 跟前面一样 好的 那么我们的模型选择问题是这样的 和之前使用测试集来选择模型不同 我们现在要使用验证集 或者说交叉验证集来选择模型 具体来讲 首先我们用第一个假设函数 也就是第一个模型 然后求代价函数的最小值 然后我们会得到这个线性模型对应的参数向量θ 和之前一样 我们还是用上表(1)来表示 这个参数是对应于线性模型的 对二次函数 我们也做同样的事情 这样可以得到θ(2) 然后是θ(3) 等等以此类推 一直到10次多项式 然后我要做的是 跟之前用测试集来预测这些假设不同 我要在交叉验证集中测试这些假设的表现 我要测出Jcv来看看 这些假设在交叉验证集中表现如何 然后我要选择的是交叉验证集误差最小的那个假设 因此 对于这个例子 假如是 四次函数的模型有最小的交叉验证误差 因此 我们就选择这个四次多项式模型 最后 这样做的意义是 参数d 别忘了参数d 是多项式的次数 d=2 d=3 一直到d=10 我们刚才做的是拟合出最好的系数d等于4 并且我们是通过交叉验证集来完成的 因此 这样一来这个参数d 这个多项式的次数 就没有跟测试集进行拟合 这样我们就回避了测试集的嫌疑 我们可以光明正大地使用测试集 来估计所选模型的泛化误差了 好的 这就是模型选择了 以及你应该怎样 将数据分成训练集、验证集和测试集 以及使用你的交叉验证集数据来选择模型 最后用测试集来评价模型的表现 最后我还想提醒的一点是 在如今的机器学习应用中 确实也有很多人是像我之前介绍的那样做的 我说过这并不是一个好的方法 也就是用测试集来选择模型 然后用同样的测试集来 评价模型的表现 报告测试误差 看起来好像还能得到比较不错的泛化误差 这的确是一种做法 但不幸的是 现在还有很多人这样做 如果你有很多很多测试集的话 这也许还能行得通 但大多数的机器学习开发人员 还是不会选择这样做 因为最佳做法还是把数据分成训练集、验证集、测试集 但我还是告诉你 在现实中确实有很大一部分人 有时会使用同样一组数据 既作为验证集 也作为测试集 也就是只有训练集和测试集 你的确可能会看到很多人选择这种方法 但如果可能的话
Bias vs. Variance
Diagnosing Bias vs. Variance
当你运行一个学习算法时 如果这个算法的表现不理想 那么多半是出现 两种情况 要么是偏差比较大 要么是方差比较大 换句话说 出现的情况要么是欠拟合 要么是过拟合问题 那么这两种情况 哪个和偏差有关 哪个和方差有关 或者是不是和两个都有关 搞清楚这一点非常重要 因为能判断出现的情况 是这两种情况中的哪一种 其实是一个很有效的指示器 指引着可以改进算法的 最有效的方法和途径 在这段视频中 我想更深入地探讨一下 有关偏差和方差的问题 希望你能对它们有一个更深入的理解 并且也能弄清楚怎样评价一个学习算法 能够判断一个算法是偏差还是方差有问题 因为这个问题对于弄清 如何改进学习算法的效果非常重要 好的 这几幅图 你已经见过很多次了 如果你用两个很简单的假设来拟合数据 比如说用一条直线 那么不足以拟合这组数据(欠拟合) 而如果你用两个很复杂的假设来拟合时 那么对训练集来说 则会拟合得很好 但又过于完美(过拟合) 而像这样的 中等复杂度的假设 比如某种二次多项式的假设 次数既不高也不低 这种假设对数据拟合得刚刚好 此时对应的的泛化误差 也是三种情况中最小的 现在我们已经掌握了 训练集 验证集和测试集的概念 我们就能更好地理解 偏差和方差的问题 具体来说 我们沿用之前所使用的 训练集误差和验证集 误差的定义 也就是平方误差 即对训练集数据进行预测 或对验证集数据进行预测 所产生的平均平方误差 下面我们来画出如下这个示意图 横坐标上表示的是 多项式的次数 因此横坐标越往右的位置 表示多项式的次数越大 那么我们来画这幅图对应的情况 d可能等于1的情况 是用很简单的函数 来进行拟合 而在右边的这个图中 水平横坐标表示 有更多更大的d值 表示更高次数的多项式 因此这些位置对应着使用 更复杂的函数来拟合你的训练集时所需要的d值 让我们来把训练集误差 和交叉验证集误差画在这个坐标中 我们先来画训练集误差 随着我们增大多项式的次数 我们将对训练集拟合得越来越好 所以如果d等于1时 对应着一个比较大的训练误差 而如果我们的多项式次数很高时 我们的训练误差就会很小 甚至可能等于0 因为可能非常拟合训练集 所以 当我们增大多项式次数时 我们不难发现 训练误差明显下降 这里我写上J下标train 来表示训练集误差 因为随着我们对数据拟合 所需多项式次数的增大 训练误差是趋于下降的 接下来我们再看交叉验证误差 事实上如果我们观察测试集误差的话 我们会得到一个和交叉验证误差 非常接近的结果 所以 我们知道 如果d等于1的话 意味着用一个很简单的函数来拟合数据 此时我们不能很好地拟合训练集(欠拟合) 也就是说 我们会得到 一个较大的交叉验证误差 而如果我们用一个中等大小的 多项式次数来拟合时 在前一张幻灯片中 我们用的d等于2 那么我们会得到一个 更小的交叉验证误差 因为我们找了一个能够更好拟合数据的次数 同样地 反过来 如果次数d太大 比如说d的值取为4 那么我们又过拟合了 我们又会得到一个较大的交叉验证误差 因此 如果你平稳地过渡这几个点 你可以绘制出一条平滑的曲线 就像这样 我用Jcv(θ)来表示 同样地 如果你画出Jtest(θ) 你也将得到一条类似的曲线 这样一幅图同时也帮助我们 更好地理解偏差和方差的概念 具体来说 假设你得出了一个学习算法 而这个算法并没有表现地 如你期望那么好 所以你的交叉验证误差或者测试集误差都很大 我们应该如何判断 此时的学习算法 正处于高偏差的问题还是高方差的问题 交叉验证误差比较大的情况 对应着曲线中的这一端 或者这一端 那么左边的这一端 对应的就是高偏差的问题 也就是你使用了一个 过于小的多项式次数 比如d等于1 但实际上我们需要一个较高的多项式次数来拟合数据 相反地 右边这一端对应的是高方差问题 也就是说 多项式次数d 对于我们的数据来讲太大了 这幅图也提示了我们 怎样区分这两种情况 具体地说 对于高偏差的情况 也就是对应欠拟合的情况 我们发现 交叉验证误差和训练误差 都会很大 因此 如果你的算法 有偏差问题的话 那么训练集误差 将会比较大 同时你可能会发现 交叉验证集误差也很大 两个误差可能很接近 或者可能验证误差稍大一点 所以如果你看到这样的组合情况 那就表示你的算法 正处于高偏差的问题 反过来 如果你的算法处于高方差的问题 那么如果你观察这里 我们会发现 Jtrain 就是训练误差 会很小 也就意味着 你对训练集数据拟合得非常好 而你的交叉验证误差 假设此时我们最小化的 是平方误差 而反过来 你的交叉验证集误差 或者说你的交叉验证集 对应的代价函数的值 将会远远大于训练集误差 这里的双大于符号 是一个数学符号 表示远远大于 用两个大于符号表示 因此如果你看见这种组合的情况 这就预示着 你的学习算法可能正处于 高方差和过拟合的情况 同时 区分这两种不同情形 的关键依据是 如果你的算法处于高偏差的情况 那么你的训练集误差会很大 因为你的假设 不能很好地拟合训练集数据 而当你处于高方差的问题时 你的训练误差 通常都会很小 并且远远小于交叉验证误差 好的 但愿这节课能让你 更清楚地理解 偏差和方差这两种问题 在之后几段视频中 我还将对偏差和误差做更多的解释 但我们之后要关注的 是诊断一个学习算法 是处于高偏差还是高方差的情况 在后面几段视频中我还将向你展示更多细节 我们将会看到 通过分清一个学习算法是处于高偏差 还是高方差 还是两种情况的结合 这能够更好地指引我们 应该采取什么样的措施 来提高学习算法的性能表现 【果壳教育无边界字幕组】门捷列夫 的关键依据是 如果你的算法处于高偏差的情况 那么你的训练集误差会很大 因为你的假设 不能很好地拟合训练集数据 而当你处于高方差的问题时 你的训练误差 通常都会很小 并且远远小于交叉验证误差 希望这节课的内容 更清楚地理解 偏差和方差这两种问题 在之后几段视频中 我还将对偏差和误差做更多的解释 但我们之后要关注的 是诊断一个学习算法 是否处于高偏差或高方差的情况 在后面几段视频中我还将向你展示更多细节 我们将会看到 通过分清一个学习算法是处于高偏差 还是高误差 还是两种情况的结合 这能够更好地指引我们 应该采取什么样的措施 来提高学习算法的性能表现
Regularization and Bias/Variance
现在你应该已经知道 算法正则化可以有效地防止过拟合 但正则化跟算法的偏差和方差 又有什么关系呢? 在这段视频中 我想更深入地 探讨一下偏差和方差的问题 讨论一下两者之间 是如何相互影响的 以及和算法的正则化之间的相互关系 假如我们要对这样一个高阶多项式进行拟合 为了防止过拟合现象 我们要使用一个正则化项 因此我们试图通过这样一个正则化项 来让参数的值尽可能小 正则化项的求和范围照例取为 j 等于1到 m 而非 j 等于0到 m 然后我们来分析以下三种情形 第一种情形是正则化参数 λ 取一个比较大的值 比如 λ 的值取为10000甚至更大 在这种情况下 所有这些参数 θ1 θ2 θ3 等等 将被大大惩罚 其结果是 这些参数的值将近似等于0 并且假设模型 h(x) 的值将等于或者近似等于 θ0 因此我们最终得到的假设函数 应该是这个样子 近似是一条平滑的直线 因此这个假设处于高偏差 对数据集欠拟合(underfit) 因此一条水平直线 对这个数据集来讲不是一个好的假设 与之对应的另一种情况是 λ值很小 比如说 λ 的值等于0 在这种情况下 如果我们要拟合一个高阶多项式的话 那么我们通常会处于过拟合(overfitting)的情况 在拟合一个高阶多项式时 如果没有进行正则化 或者正则化程度很微小的话 我们通常会得到高方差和过拟合的结果 因为 λ 的值等于0相当于没有正则化项 因此会对假设过拟合 只有当我们取一个中间大小的 既不大也不小的 λ 值时 我们才会得到一组合理的 对数据刚好拟合的 θ 参数值 那么我们应该怎样自动地选择出一个最合适的正则化参数 λ 呢? 重申一下 我们的模型和学习参数 以及最优化目标是这样的 让我们假设在使用正则化的情形中 定义 Jtrain(θ) 为另一种不同的形式 同样定义为最优化目标 但不使用正则化项 在先前的授课视频中 当我们没有使用正则化时 我们定义的Jtrain(θ) 就是代价函数J(θ) 但当我们使用正则化多出这个 λ 项时 我们就将训练集误差 也就是Jtrain 定义为 训练集数据预测误差的平方求和 或者说是训练集的平均误差平方和 但不考虑正则化项 与此类似 我们来定义交叉验证集误差和测试集误差 和之前一样定义为 对交叉验证集和测试集进行预测的平均误差平方和 总结一下 我们对于训练误差Jtrain Jcv Jtest的定义 都是平均误差平方和 或者准确地说 是训练集 验证集和测试集进行预测 在不使用正则化项时 平均误差平方和的一半 下面就是我们自动选取正则化参数 λ 的方法 通常我的做法是 选取一系列我想要尝试的 λ 值 因此首先我可能考虑不使用正则化的情形 以及一系列我可能会试的值 比如说我可能从0.01 0.02 0.04开始 一直试下去 通常我会将步长设为2倍速度增长 直到一个比较大的值 在本例中以两倍步长递增的话 我们最终取值10.24 实际上我们取的是10 但已经非常接近了 因为小数点后的24对最终的结果不会有太大影响 因此 这样我就得到了12个不同的正则化参数 λ 对应的12个不同的模型 当然了 你也可以试小于0.01的值或者大于10的值 但在这里我就不讨论这些情况了 得到这12组模型后 接下来我们要做的事情是 选用第一个模型 也就是 λ 等于0 然后最小化我们的代价函数 J(θ) 这样我们就得到了某个参数向量 θ 与之前视频的做法类似 我使用θ上标(1) 来表示第一个参数向量θ 然后我再取第二个模型 λ 等于0.01的模型 最小化代价方差 当然现在 λ 等于0.01 那么会得到一个完全不同的参数向量 θ 用 θ(2)来表示 同理 接下来我会得到 θ(3) 对应于我的第三个模型 以此类推 一直到最后一个 λ 等于10或10.24的模型 对应 θ(12) 接下来我就可以用交叉验证集来评价这些假设和参数了 因此我可以从第一个模型开始 然后是第二个模型 对每一个不同的正则化参数 λ 进行拟合 然后用交叉验证集来评价每一个模型 也即测出每一个参数 θ 在交叉验证集上的平均误差平方和 然后我就选取这12个模型中交叉验证集误差最小的 那个模型作为最终选择 对于本例而言 假如说 最终我选择了 θ(5) 也就是五次多项式 因为此时的交叉验证集误差最小 做完这些 最后 如果我想看看该模型在测试集上的表现 我可以用经过学习得到的模型 θ(5) 来测出它对测试集的预测效果如何 再次重申 这里我们依然是用交叉验证集来拟合模型 这也是为什么我之前预留了一部分数据作为测试集的原因 这样我就可以用这部分测试集比较准确地估计出 我的参数向量 θ 对于新样本的泛化能力 这就是模型选择在选取正则化参数 λ 时的应用 在这段视频中我想讲的最后一个问题是 当我们改变正则化参数 λ 的值时 交叉验证集误差和训练集误差 会随之发生怎样的变化 我想提醒一下 我们最初的代价函数 J(θ) 但在这里我们把训练误差 定义为不包括正则化项 交叉验证集误差也定义为不包括正则化项 我要做的是绘制出 Jtrain和 Jcv 的曲线 表达的是随着我增大正则化项参数 λ 的值 看看我的假设 在训练集上的表现如何变化 以及在交叉验证集上表现如何变化 就像我们之前看到的 如果 λ 的值很小 那也就是说我们几乎没有使用正则化 因此我们有很大可能处于过拟合 而如果 λ 的值取的很大的时候 也就是说取值在横坐标的右端 那么由于 λ 的值很大 我们很有可能处于高偏差的问题 所以 如果你画出 Jtrain 和 Jcv 的曲线 你就会发现 当 λ 的值取得很小时 对训练集的拟合相对较好 因为没有使用正则化 因此 对于 λ 值很小的情况正则化项可以忽略 你只需要对平方误差求最小值即可 所以当 λ 值很小时 你最终能得到一个值很小的Jtrain 而如果 λ 的值很大时你将处于高偏差问题 不能对训练集很好地拟合 因此你的误差值可能位于这个位置 因此 当 λ 增大时 训练集误差Jtrain的值 会趋于上升 因为 λ 的值比较大时对应着高偏差的问题 此时你连训练集都不能很好地拟合 反过来 当 λ 的值取得很小的时候 你的数据能随意地与高次多项式很好地拟合 而交叉验证集误差的曲线是这样的 在曲线的右端 当 λ 的值取得很大时 我们会处于欠拟合问题 因此这对应着偏差问题 那么此时交叉验证集误差将会很大 我写在这里 这是交叉验证集误差Jcv(θ) 由于高偏差的原因我们不能很好地拟合 我们的假设不能在交叉验证集上表现地比较好 而曲线的左端对应的是高方差问题 此时我们的 λ 值取得很小很小 因此我们会对数据过度拟合 所以由于过拟合的原因 交叉验证集误差也会很大 好的 这就是当我们改变正则化参数 λ 的值时 交叉验证集误差和训练集误差随之发生的变化 当然 在中间取的某个 λ 的值 表现得刚好合适 这种情况下表现最好 交叉验证集误差或者测试集误差都很小 当然由于我在这里画的图显得太卡通 也太理想化了 对于真实的数据 你得到的曲线可能比这看起来更凌乱 会有很多的噪声 对某个实际的数据集 你或多或少能看出像这样的一个趋势 通过绘出这条曲线 通过交叉验证集误差的变化趋势 你可以用自己选择出 或者编写程序自动得出 能使交叉验证集误差最小的那个点 然后选出那个与之对应的参数 λ 的值 当我在尝试为学习算法选择正则化参数 λ 的时候 我通常都会画出像这样一个图 帮助我更好地理解各种情况 同时也帮助我确认 我选择的正则化参数值到底好不好 希望这节课的内容让你更深入地理解了正则化 以及它对学习算法的偏差和方差的影响 到目前为止你已经从不同角度认识了方差和偏差问题 在下一节视频中我要做的是 基于我们已经介绍过的所有这些概念 将它们结合起来 建立我们的诊断法 也称为学习曲线 这种方法通常被用来诊断一个学习算法 到底是处于偏差问题还是方差问题 还是两者都有 【果壳教育无边界字幕组】翻译/时间轴:所罗门捷列夫 假如说 最终我选择了theta(5) 也就是五次多项式 因为此时的交叉验证集误差最小 做完这些 最后 如果我想看看该模型 在测试集上的表现 我可以用经过学习 得到的模型theta(5) 来测出它对测试集的 预测效果如何 再次重申一下 这里我们依然是用 交叉验证集来拟合模型 这也是为什么我之前 预留了一部分数据 作为测试集的原因 这样我就可以用这部分测试集 比较准确地估计出 我的参数向量theta 对于新样本的泛化能力 这就是模型选择在选取 正则化参数lambda时的应用 在这段视频中 我想讲的最后一个问题是 当我们改变 正则化参数lambda的值时 交叉验证集误差 和训练集误差会随之 发生怎样的变化 我想提醒一下 我们最初的代价函数J(θ) 原来是这样的形式 但在这里我们把训练误差 定义为不包括正则化项 交叉验证集误差 也定义为不包括 正则化项 我要做的是 绘制出Jtrain和Jcv的曲线 随着我增大正则化项参数 lambda的值 看看我的假设 在训练集上的表现如何变化 以及在交叉验证集上 表现如何变化 就像我们之前看到的 如果正则化项参数 lambda的值很小 那也就是说我们几乎没有使用正则化 因此我们有很大可能处于过拟合 而如果lambda的值 取的很大的时候 也就是说取值在 横坐标的右端 那么由于lambda的值很大 我们很有可能处于高偏差的问题 所以 如果你画出 Jtrain和Jcv的曲线 你就会发现 当lambda的值取得很小时 对训练集的拟合相对较好 因为没有使用正则化 因此 对于lambda值很小的情况 正则化项基本可以忽略 你只需要对平方误差 做最小化处理即可 所以当lambda值很小时 你最终能得到一个 值很小的Jtrain 而如果lambda的值很大时 你将处于高偏差问题 不能对训练集很好地拟合 因此你的误差值可能位于这个位置 因此 当lambda增大时 训练集误差Jtrain的值 会趋于上升 因为lambda的值比较大时 对应着高偏差的问题 此时你连训练集都不能很好地拟合 反过来 当lambda的值 取得很小的时候 你的数据能随意地与高次多项式 很好地拟合 交叉验证集误差的曲线是这样的 在曲线的右端 当lambda的值 取得很大时 我们会处于欠拟合问题 也对应着偏差问题 那么此时交叉验证集误差 将会很大 我写在这里 这是交叉验证集误差Jcv 由于高偏差的原因我们不能很好地拟合 我们的假设不能在交叉验证集上表现地比较好 而曲线的左端对应的是高方差问题 此时我们的lambda值 取得很小很小 因此我们会对数据过度拟合 所以由于过拟合的原因 交叉验证集误差Jcv 结果也会很大 好的 这就是 当我们改变正则化参数 lambda的值时 交叉验证集误差 和训练集误差 随之发生的变化 当然 在中间取的某个 lambda的值 表现得刚好合适 这种情况下表现最好 交叉验证集误差 或者测试集误差都很小 当然由于我在这里画的图 显得太卡通 也太理想化了 对于真实的数据 你得到的曲线可能 比这看起来更凌乱 会有很多的噪声 对某个实际的数据集 你或多或少能看出 像这样的一个趋势 通过绘出这条曲线 通过交叉验证集误差的变化趋势 你可以用自己选择出 或者编写程序自动得出 能使交叉验证集误差 最小的那个点 然后选出那个与之对应的 参数lambda的值 当我在尝试为学习算法 选择正则化参数 lambda的时候 我通常都会得出 类似这个图的结果 帮助我更好地理解各种情况 同时也帮助我确认 我选择的正则化参数值 到底好不好 希望这节课的内容 让你更深入地理解了正则化 以及它对学习算法的 偏差和方差的影响 到目前为止你已经从不同角度 见识了方差和偏差问题 在下一节视频中 我要做的是 基于我们已经浏览过的 所有这些概念 将它们结合起来 建立我们的诊断法 也称为学习曲线 这种方法通常被用来 诊断一个学习算法 到底是处于偏差问题 还是方差问题 还是两者都有
Learning Curves
本节课我们介绍学习曲线 绘制学习曲线非常有用 也许你想检查你的学习算法 运行是否一切正常 或者你希望改进算法的表现或效果 那么学习曲线 就是一种很好的工具 我经常使用学习曲线 来判断某一个学习算法 是否处于偏差 方差问题 或是二者皆有 下面我们就来介绍学习曲线 为了绘制一条学习曲线 我通常先绘制出Jtrain 也就是训练集数据的 平均误差平方和 或者Jcv 也即交叉验证集数据的 平均误差平方和 我要将其绘制成一个 关于参数m的函数 也就是一个关于训练集 样本总数的函数 所以m一般都是一个常数 比如m等于100 表示100组训练样本 但我要自己取一些m的值 也就是说我要自行对m的取值 做一点限制 比如说我取10 20或者 30 40组训练集 然后绘出训练集误差 以及交叉验证集误差 好的 那么我们来看看 这条曲线绘制出来是什么样子 假设我只有一组训练样本 也即m=1 正如第一幅图中所示 并且假设使用二次函数来拟合模型 那么由于我只有一个训练样本 拟合的结果很明显会很好 是吧 用二次函数来拟合 对这一个训练样本拟合 其误差一定为0 如果有两组训练样本 二次函数也能很好地拟合 即使是使用正则化 拟合的结果也会很好 而如果不使用正则化的话 那么拟合效果绝对棒极了 如果我用三组训练样本的话 好吧 看起来依然能很好地 用二次函数拟合 也就是说 当m等于1 m=2 或m=3时 对训练集数据进行预测 得到的训练集误差 都将等于0 这里假设我不使用正则化 当然如果使用正则化 那么误差就稍大于0 顺便提醒一下 如果我的训练集样本很大 而我要人为地限制训练集 样本的容量 比如说这里 我将m值设为3 然后我仅用这三组样本进行训练 然后对应到这个图中 我只看对这三组训练样本 进行预测得到的训练误差 也是和我模型拟合的三组样本 所以即使我有100组训练样本 而我还是想绘制 当m等于3时的训练误差 那么我要关注的仍然是 对这三组训练样本进行预测的误差 同样 这三组样本也是我们用来拟合模型的三组样本 所有其他的样本 我都在训练过程中选择性忽略了 好的 总结一下 我们现在已经看到 当训练样本容量m很小的时候 训练误差也会很小 因为很显然 如果我们训练集很小 那么很容易就能把 训练集拟合到很好 甚至拟合得天衣无缝 现在我们来看 当m等于4的时候 好吧 二次函数似乎也能 对数据拟合得很好 那我们再看 当m等于5的情况 这时候再用二次函数来拟合 好像效果有下降但还是差强人意 而当我的训练集越来越大的时候 你不难发现 要保证使用二次函数 的拟合效果依然很好 就显得越来越困难了 因此 事实上随着训练集容量的增大 我们不难发现 我们的平均训练误差 是逐渐增大的 因此如果你画出这条曲线 你就会发现 训练集误差 也就是 对假设进行预测的误差平均值 随着m的增大而增大 再重复一遍对这一问题的理解 当训练样本很少的时候 对每一个训练样本 都能很容易地拟合到很好 所以训练误差将会很小 而反过来 当m的值逐渐增大 那么想对每一个训练样本都拟合到很好 就显得愈发的困难了 因此训练集误差就会越来越大 那么交叉验证集误差的情况如何呢 好的 交叉验证集误差 是对完全陌生的交叉验证集数据 进行预测得到的误差 那么我们知道 当训练集很小的时候 泛化程度不会很好 意思是不能很好地适应新样本 因此这个假设 就不是一个理想的假设 只有当我使用 一个更大的训练集时 我才有可能 得到一个能够更好拟合数据的 可能的假设 因此 你的验证集误差和 测试集误差 都会随着训练集样本容量m的增加 而减小 因为你使用的数据越多 你越能获得更好地泛化表现 或者说对新样本的适应能力更强 因此 数据越多 越能拟合出合适的假设 所以 如果你把Jtrain和Jcv绘制出来 就应该得到这样的曲线 现在我们来看看 当处于高偏差或者高方差的情况时 这些学习曲线 又会变成什么样子 假如你的假设处于高偏差问题 为了更清楚地解释这个问题 我要用一个简单的例子来说明 也就是用一条直线 来拟合数据的例子 很显然一条直线不能很好地拟合数据 所以最后得到的假设很有可能是这样的 现在我们来想一想 如果我们增大训练集样本容量 会发生什么情况呢 所以现在不像画出的这样 只有这五组样本了 我们有了更多的训练样本 那么如果你用一条直线来拟合 不难发现 还是会得到类似的一条直线假设 我的意思是 刚才的情况用一条直线不能很好地拟合 而现在把样本容量扩大了 这条直线也基本不会变化太大 因为这条直线是对这组数据 最可能也是最接近的拟合 但一条直线再怎么接近 也不可能对这组数据进行很好的拟合 所以 如果你绘出交叉验证集误差 应该是这样子的 最左端表示训练集样本容量很小 比如说只有一组样本 那么表现当然很不好 而随着你增大训练集样本数 当达到某一个容量值的时候 你就会找到那条最有可能 拟合数据的那条直线 并且此时即便 你继续增大训练集的 样本容量 即使你不断增大m的值 你基本上还是会得到的一条差不多的直线 因此 交叉验证集误差 我把它标在这里 或者测试集误差 将会很快变为水平而不再变化 只要训练集样本容量值达到 或超过了那个特定的数值 交叉验证集误差和测试集误差就趋于不变 这样你会得到最能拟合数据的那条直线 那么训练误差又如何呢 同样 训练误差一开始也是很小的 而在高偏差的情形中 你会发现训练集误差 会逐渐增大 一直趋于接近 交叉验证集误差 这是因为你的参数很少 但当m很大的时候 数据太多 此时训练集和交叉验证集的 预测效果将会非常接近 这就是当你的学习算法处于 高偏差情形时 学习曲线的大致走向 最后补充一点 高偏差的情形 反映出的问题是 交叉验证集和训练集 误差都很大 也就是说 你最终会得到一个 值比较大Jcv 和Jtrain 这也得出一个很有意思的结论 那就是 如果一个学习算法 有很大的偏差 那么当我们选用更多的训练样本时 也就是在这幅图中 随着我们增大横坐标 我们发现交叉验证集误差的值 不会表现出明显的下降 实际上是变为水平了 所以如果学习算法 正处于高偏差的情形 那么选用更多的训练集数据 对于改善算法表现无益 正如我们右边的 这两幅图所体现的 这里我们只有五组训练样本 然后我们找到这条直线来拟合 然后我们增加了更多的训练样本 但我们仍然得到几乎一样的 一条直线 因此如果学习算法 处于高偏差时 给我再多的训练数据也于事无补 交叉验证集误差或测试集误差 也不会降低多少 所以 能够看清你的算法正处于 高偏差的情形 是一件很有意义的事情 因为这样可以让你避免 把时间浪费在 想收集更多的训练样本 因为再多的数据也是无意义的 接下来我们再来看看 当学习算法正处于高方差的时候 学习曲线应该是什么样子的 首先我们来看 训练集误差 如果你的训练集样本容量很小 比如像图中所示情形 只有五组训练样本 如果我们用很高阶次的 多项式来拟合 比如这里我用了100次的多项式函数 当然不会有人这么用的 这里只是演示 并且假设我们使用 一个很小的lambda值 可能不等于0 但足够小的lambda 那么很显然 我们会对这组数据 拟合得非常非常好 因此这个假设函数对数据过拟合 所以 如果训练集 样本容量很小时 训练集误差Jtrain 将会很小 随着训练集样本容量的增加 可能这个假设函数仍然会 对数据或多或少 有一点过拟合 但很明显此时要对数据很好地拟合 显得更加困难和吃力了 所以 随着训练集样本容量的增大 我们会发现Jtrain的值 会随之增大 因为当训练样本越多的时候 我们就越难跟训练集数据拟合得很好 但总的来说训练集误差还是很小 交叉验证集误差又如何呢 好的 在高方差的情形中 假设函数对数据过拟合 因此交叉验证集误差 将会一直都很大 即便我们选择一个 比较合适恰当的 训练集样本数 因此交叉验证集误差 画出来差不多是这样的 所以算法处于高方差情形 最明显的一个特点是 在训练集误差 和交叉验证集误差之间 有一段很大的差距 而这个曲线图也反映出 如果我们要考虑增大训练集的样本数 也就是在这幅图中 向右延伸曲线 我们大致可以看出 这两条学习曲线 蓝色和红色的两条曲线 正在相互靠近 因此 如果我们将曲线 向右延伸出去 那么似乎 训练集误差很可能会 逐渐增大 而交叉验证集误差 则会持续下降 当然我们最关心的还是交叉验证集误差 或者测试集误差 对吧 所以从这幅图中 我们基本可以预测 如果继续增大训练样本的数量 将曲线向右延伸 交叉验证集误差将会 逐渐下降 所以 在高方差的情形中 使用更多的训练集数据 对改进算法的表现 事实上是有效果的 这同样也体现出 知道你的算法正处于 高方差的情形 也是非常有意义的 因为它能告诉你 是否有必要花时间 来增加更多的训练集数据 好的 在前一页和这一页幻灯片中 我画出的学习曲线 都是相当理想化的曲线 针对一个实际的学习算法 如果你画出学习曲线的话 你会看到基本类似的结果 就像我在这里画的一样 虽然如此 有时候你也会看到 带有一点噪声或干扰的曲线 但总的来说 像这样画出学习曲线 确实能帮助你 看清你的学习算法 是否处于高偏差 高方差 或二者皆有的情形 所以当我打算 改进一个学习算法 的表现时 我通常会进行的一项工作 就是画出这些学习曲线 一般来讲 这项工作会让你 更轻松地看出偏差或方差的问题 在下一节视频中 我们将介绍如何判断 是否应采取具体的某个行为 来改进学习算法的表现
Deciding What to Do Next Revisited
我们已经介绍了怎样评价一个学习算法 我们讨论了模型选择问题 偏差和方差的问题 那么这些诊断法则怎样帮助我们判断 哪些方法可能有助于 改进学习算法的效果 而哪些可能是徒劳的呢 让我们再次回到最开始的例子 在那里寻找答案 这就是我们之前的例子 我们使用正则化的线性回归拟合模型 却发现该算法没有达到预期效果 我们提到我们有如下这些选择 那么如何判断 哪些方法更可能是有效的呢 第一种可供选择的方法 是使用更多的训练集数据 这种方法对于高方差的情况 是有帮助的 也就是说 如果你的模型不处于高方差问题 而是处于高偏差的时候 那么通过前面的视频 我们已经知道 获取更多的训练集数据 并不会有太明显的帮助 所以 要选择第一种方法 你应该先画出 学习曲线 然后看出你的模型 应该至少有那么一点方差问题 也就是说你的交叉验证集误差 应该比训练集误差大一点 第二种方法情况又如何呢 第二种方法是 少选几种特征 这同样是对高方差时有效 换句话说 如果你通过绘制学习曲线 或者别的什么方法 看出你的模型处于高偏差问题 那么切记 千万不要浪费时间 试图从已有的特征中 挑出一小部分来使用 因为你已经发现高偏差的问题了 使用更少的特征不会有任何帮助 反过来 如果你发现 从你的学习曲线 或者别的某种诊断图中 你看出了高方差的问题 那么恭喜你 花点时间挑选出一小部分合适的特征吧 这是把时间用在了刀刃上 方法三 选用更多的特征又如何呢 通常来讲 尽管不是所有时候都适用 但增加特征数 一般可以帮助解决高偏差问题 所以如果你需要增加 更多的特征时 一般是由于你现有的 假设函数太简单 因此我们才决定增加一些 别的特征来让假设函数 更好地拟合训练集 类似的 增加更多的多项式特征 这实际上也是属于增加特征 因此也是用于 修正高偏差问题 具体来说 如果你画出的学习曲线告诉你 你还是处于高方差问题 那么采取这种方法 就是浪费时间 最后 增大和减小λ 这种方法尝试起来很方便 我想 尝试这个方法 不至于花费你几个月时间 但我们已经知道 减小λ可以修正高偏差 如果我说的你还不清楚的话 我建议你暂停视频 仔细回忆一下 想明白 减小λ的值 为何有助于修正高偏差 而增大λ的值为何解决高方差 如果你确实不明白 其中的原因 那就暂停一下好好想想 直到真的弄清楚这个道理 或者看看 上一节视频最后 我们绘制的学习曲线 试着理解清楚 为什么是那样的 最后 我们回顾一下 这几节课介绍的这些内容 并且看看它们和神经网络的联系 我想介绍一些 很实用的经验或建议 这些也是我平时为神经网络模型 选择结构或者连接形式的一些技巧 当你在进行神经网络拟合的时候 如果你要进行神经网络的拟合 比如说 一个相对比较简单的神经网络模型 相对来讲 它的隐藏单元比较少 甚至只有一个隐藏单元 如果你要进行神经网络的拟合 其中一个选择是 选用一个相对简单的网络结构 比如说只有一个 隐藏层 或者可能相对来讲 比较少的隐藏单元 因此像这样的一个简单的神经网络 参数就不会很多 很容易出现欠拟合 这种比较小型的神经网络 其最大优势在于计算量较小 与之相对的另一种情况 是相对较大型的神经网络结构 要么隐藏层单元比较多 比如这一层中的隐藏单元数就很多 要么隐藏层比较多 因此这种比较复杂的神经网络 参数一般较多 也更容易出现过拟合 这种结构的一大劣势 也许不是主要的 但还是需要考虑 那就是当网络中的 神经元数量很多的时候 这种结构会显得 计算量较大 虽然有这个情况 但通常来讲这不是大问题 这种大型网络结构最主要的问题 还是它更容易出现过拟合现象 事实上 如果你经常应用神经网络 特别是大型神经网络的话 你就会发现越大型的网络性能越好 但如果发生了过拟合 你可以使用正则化的方法 来修正过拟合 一般来说 使用一个大型的神经网络 并使用正则化来修正过拟合问题 通常比使用一个小型的神经网络 效果更好 但主要可能出现的问题 是计算量相对较大 最后 你还需要选择 隐藏层的层数 你是应该用一个 隐藏层呢 还是应该用三个呢 就像我们这里画的 或者还是用两个隐藏层呢 通常来说 正如我在前面的视频中讲过的 默认的情况是 使用一个隐藏层 但是如果你确实想要选择 多个隐藏层 你也可以试试 把数据分割为训练集 验证集 和测试集 然后使用交叉验证的方法 比较一个隐藏层的神经网络 然后试试两个 三个隐藏层 以此类推 然后看看哪个神经网络 在交叉验证集上表现得最理想 也就是说 你得到了三个神经网络模型 分别有一个 两个 三个隐藏层 然后你对每一个模型 都用交叉验证集数据进行测试 算出三种情况下的 交叉验证集误差Jcv 然后选出你认为最好的 神经网络结构 好了 这就是 偏差和方差问题 以及诊断该问题的学习曲线方法 在改进学习算法的表现时 你可以充分运用 以上这些内容来判断 哪些途径可能是有帮助的 而哪些方法可能是无意义的 如果你理解了以上几节视频中 介绍的内容 并且懂得如何运用 那么你已经可以使用机器学习方法有效的解决实际问题了 你也能像硅谷的 大部分机器学习从业者一样 他们每天的工作就是 使用这些学习算法 来解决众多实际问题 我希望这几节中 提到的一些技巧 关于方差 偏差 以及学习曲线为代表的诊断法 能够真正帮助你更有效率地 应用机器学习 让它们高效地工作
Machine Learning System Design
Building a Spam Classifier
Prioritizing What to Work On
在接下来的视频中 我将谈到机器学习系统的设计 这些视频将谈及 在设计复杂的机器学习系统时 你将遇到的 主要问题 同时我们会试着 给出一些关于 如何巧妙构建一个复杂的机器学习系统的建议 接下来的视频 可能看起来 有点不连贯 因为这些视频会涉及 一些你在设计机器学习系统时 可能会遇到的不同问题 虽然 下面的课程的 的数学性可能不是那么强 但是我认为我们将要讲到的这些东西 是非常有用的 可能在构建大型的机器学习系统时 节省大量的时间 具体的说 我首先要讲的是 当我们在进行机器学习时 着重要考虑什么问题 首先我要举一个 垃圾邮件分类的例子 假如你想建立一个垃圾邮件分类器 看这些垃圾邮件与 非垃圾邮件的例子 左边这封邮件想向你推销东西 注意 这封垃圾邮件 有意的拼错一些单词 就像 "Med1cine" 中有一个1 "m0rtgage"里有个0 右边的邮件 显然不是一个垃圾邮件 实际上这是我弟弟写给我的 假设我们已经有一些 加过标签的训练集 包括标注的垃圾邮件 表示为y=1 和非垃圾邮件 表示为y=0 我们如何 以监督学习的方法来构造一个分类器 来区分垃圾邮件和非垃圾邮件呢? 为了应用监督学习 我们首先 必须确定的是 如何用邮件的特征 构造向量x 给出训练集中的 特征x和标签y 我们就能够训练出某种分类器 比如用逻辑回归的方法 这里有一种选择 邮件的一些特征变量的方法 比如说我们可能会想出 一系列单词 或者成百上千的单词 我们可以认为这些单词 能够用来区分垃圾邮件或非垃圾邮件 比如说 如果有封邮件 包含单词"deal(交易)" 那么它就很有可能是一封垃圾邮件 同时 包含单词"buy(买)"的邮件 也很有可能是一封垃圾邮件 包含"discount(折扣)"的邮件 也很有可能是垃圾邮件 如果一封邮件中 包含了我的名字"Andrew" 这有可能是一个知道我的人写的 这说明这封邮件 不太可能是垃圾邮件 因为某些原因 我认为 "now(现在)"这个单词表明了 这封邮件可能并不是垃圾邮件 因为我经常收到一些很紧急的邮件 当然还有别的单词 我们可以选出这样成百上千的单词 给出一封这样的邮件 我们可以将这封邮件 用一个特征向量 来表示 方法如下 现在我列出一些 之前选好的单词 然后按字典序排序 其实并不是一定要排序的啦 你看 这些是之前的单词 像“discount” 等等 还有单词"now" 等等 看看这个例子 右边的这封邮件 我准备 检查一下这些词汇 看它们是否 出现在这封邮件中 我用一个 特征向量x 表示右边的这封邮件 我的名字没有出现 因此这里是0 单词"buy(购买)"出现了 所以这里是1 注意在向量里面只有1或0 表示有没有出现 所以尽管"buy"出现了两次 这里仍然只是1 注意我不会去统计每个词出现的次数 单词"deal"也出现了 所以这里也是1 单词"discount"并没有出现 至少在这封邮件里是这样 以此类推 单词"now"出现了 所以我在特征向量中 依据对应的单词是否出现 填上0和1 在这个例子中 因为我选择了100个单词 用于表示是否可能为垃圾邮件 所以 这个特征向量x 的维度是100 并且 如果这个特定的单词 即单词 j 出现在 这封邮件中 那么每一个特征变量 Xj 的值为1 反之 Xj为0 好 这样我们就可以使用特征向量 来表示这封邮件 顺便说一句 虽然我所描述的这个过程是我自己 选取的100个单词 但是在实际工作中 最普遍的做法是 遍历整个训练集 然后 在训练集中 选出出现次数最多的n个单词 n一般介于10,000和50,000之间 然后把这些单词 作为你要用的特征 因此不同于手动选取 我们只用遍历 训练样本 然后选出出现频率最高的词语 差不多是10,000到50,000个单词 这些单词会构成特征 这样你就可以用它们 来做垃圾邮件分类 如果你正在构造一个垃圾邮件分类器 你应该会面对这样一个问题 那就是 你最该去使用哪一种 改进你的方法 从而使得你的垃圾邮件分类器具有较高的准确度 从直觉上讲 是要收集大量的数据 生成了这个叫做 data 的对象 是吧? 事实上确实好多人这么做 很多人认为 收集越多的数据 算法就会表现的越好 事实上 就垃圾邮件分类而言 有一个叫做"Honey Pot"的项目 它可以建立一个 假的邮箱地址 故意将这些地址 泄露给发垃圾邮件的人 这样就能收到大量的垃圾邮件 你看 这样的话 我们就能得到非常多的垃圾邮件来训练学习算法 但是 在前面的课程中我们知道 大量的数据可能会有帮助 也可能没有 对于大部分的机器学习问题 还有很多办法 用来提升机器学习的效果 比如对于垃圾邮件而言 也许你会想到 用更复杂的特征变量 像是邮件的路径信息 这种信息通常会出现在邮件的标题中 因此 垃圾邮件发送方在发送垃圾邮件时 他们总会试图 让这个邮件的来源变得模糊一些 或者是 用假的邮件标题 或者通过不常见的服务器 来发送邮件 用不常见的路由 他们就能给你发送垃圾邮件 而且这些信息也有可能包含在邮件标题部分 因此可以想到 我们可以通过邮件的标题部分 来构造更加复杂的特征 来获得一系列的邮件路由信息 进而判定这是否是一封垃圾邮件 你还可能会想到别的方法 比如 从邮件的正文出发 寻找一些复杂点的特征 例如 单词"discount" 是否和单词"discounts"是一样的 又比如 单词"deal(交易)"和"dealer(交易商)"是否也应视为等同 甚至 像这个例子中 有的单词小写有的大写 或者我们是否应该用标点符号来构造复杂的特征变量 因为垃圾邮件可能会更多的使用感叹号 这些都不一定 同样的 我们也可能构造 更加复杂的算法来检测 或者纠正那些故意的拼写错误 例如 "m0rtgage" "med1cine" "w4tches" 因为垃圾邮件发送方确实这么做了 因为如果你将4放到"w4tches"中 那么 用我们之前提到的 简单的方法 垃圾邮件分类器不会把"w4tches" 和"watches" 看成一样的 这样我们就很难区分这些 故意拼错的垃圾邮件 发垃圾邮件的也很机智 他们这么做就逃避了一些过滤 当我们使用机器学习时 总是可以“头脑风暴”一下 想出一堆方法来试试 就像这样 顺带一提 我有一段时间 研究过垃圾邮件分类的问题 实际上我花了很多时间来研究这个 尽管我能够理解 垃圾邮件分类的问题 我确实懂一些这方面的东西 但是 我还是很难告诉你 这四种方法中 你最该去使用哪一种 事实上 坦白地说 最常见的情况是 一个研究小组 可能会随机确定其中的一个方法 但是有时候 这种方法 并不是最有成效的 你知道 你只是随机选择了其中的一种方法 实际上 当你需要通过 头脑风暴来想出 不同方法来尝试去提高精度的时候 你可能已经超越了很多人了 令人难过的是 大部分人 他们并不尝试着 列出可能的方法 他们做的 只是 某天早上醒来 因为某些原因 有了一个突发奇想 "让我们来试试 用Honey Pot项目 收集大量的数据吧" 不管出于什么奇怪的原因 早上的灵机一动 还是随机选一个 然后干上大半年 但是我觉得我们有更好的方法 是的 我们将在随后的课程中 讲到这个 那就是误差分析 我会告诉你 怎样用一个 更加系统性的方法 从一堆不同的方法中 选取合适的那一个 因此 你更有可能选择 一个真正的好方法 能让你花上几天几周 甚至是几个月 去进行深入的研究
Error Analysis
在上一节课中 我讲到了应当怎样面对 机器学习问题 有很多提高算法表现的方法 在本次课程中 我们将会讲到 误差分析(error analysis)的概念 这会帮助你 更系统地做出决定 如果你准备 研究机器学习的东西 或者构造机器学习应用程序 最好的实践方法 不是建立一个 非常复杂的系统 拥有多么复杂的变量 而是 构建一个简单的算法 这样你可以很快地实现它 每当我研究 机器学习的问题时 我最多只会花一天的时间 就是字面意义上的24小时 来试图很快的把结果搞出来 即便效果不好 坦白的说 就是根本没有用复杂的系统 但是只是很快的得到的结果 即便运行得不完美 但是也把它运行一遍 最后通过交叉验证来检验数据 一旦做完 你可以画出学习曲线 这个我们在前面的课程中已经讲过了 通过画出学习曲线 以及检验误差 来找出 你的算法是否有 高偏差和高方差的问题 或者别的问题 在这样分析之后 再来决定用更多的数据训练 或者加入更多的特征变量是否有用 这么做的原因是 这在你刚接触机器学习问题时 是一个很好的方法 你并不能 提前知道 你是否需要复杂的特征变量 或者你是否需要 更多的数据 还是别的什么 提前知道你应该做什么 是非常难的 因为你缺少证据 缺少学习曲线 因此 你很难知道 你应该把时间花在什么地方来提高算法的表现 但是当你实践一个 非常简单即便不完美的 方法时 你可以通过画出学习曲线来做出进一步的选择 你可以 用这种方式 来避免一种 电脑编程里的过早优化问题 这种理念是 我们必须 用证据来领导我们的决策 怎样分配自己的时间来优化算法 而不是仅仅凭直觉 凭直觉得出的东西一般总是错误的 除了画出学习曲线之外 一件非常有用的事是 误差分析 我的意思是说 当我们在构造 比如构造垃圾邮件分类器时 我会看一看 我的交叉验证数据集 然后亲自看一看 哪些邮件被算法错误地分类 因此 通过这些 被算法错误分类的垃圾邮件 与非垃圾邮件 你可以发现某些系统性的规律 什么类型的邮件总是被错误分类 经常地 这样做之后 这个过程能启发你 构造新的特征变量 或者告诉你 现在 这个系统的短处 然后启发你 如何去提高它 具体地说 这里有一个例子 假设你正在构造一个 垃圾邮件分类器 你拥有500个实例 在交叉验证集中 假设在这个例子中 该算法有非常高的误差率 它错误分类了 一百个交叉验证实例 所以我要做的是 人工检查这100个错误 然后手工为它们分类 基于例如 这些是什么类型的邮件 哪些变量 能帮助这个算法来正确分类它们 明确地说 通过鉴定这是哪种类型的邮件 通过检查 这一百封错误分类的邮件 我可能会发现 最容易被误分类的邮件 可能是 有关药物的邮件 基本上这些邮件都是卖药的 或者 卖仿品的 比如卖假表 或者一些骗子邮件 又叫做钓鱼邮件 等等 所以 在检查哪些邮件被错误分类的时候 我会看一看每封邮件 数一数 比如 在这100封错误归类的邮件中 我发现有12封 错误归类的邮件是和卖药有关的邮件 4封 是推销仿品的 推销假表或者别的东西 然后我发现 有53封邮件 是钓鱼邮件 诱骗你 告诉他们你的密码 剩下的31封别的类型的邮件 通过算出 每个类别中 不同的邮件数 你可能会发现 比如 该算法在 区分钓鱼邮件的时候 总是表现得很差 这说明 你应该花更多的时间 来研究这种类型的邮件 然后 看一看你是否能通过构造更好的特征变量 来正确区分这种类型的邮件 同时 我要做的是 看一看哪些特征变量 可能会帮助算法正确地分类邮件 我们假设 能帮助我们提高 邮件分类表现 的方法是 检查有意的拼写错误 不寻常的邮件路由来源 以及垃圾邮件特有的标点符号方式 比如很多感叹号 与之前一样 我会手动地浏览这些邮件 假设有5封这种类型的邮件 16封这种类型的 32封这种类型的 以及一些别的类型的 如果 这就是你从交叉验证中得到的结果 那么 这可能说明 有意地拼写错误出现频率较少 这可能并不值得 你花费时间 去编写算法来检测这种类型的邮件 但是如果你发现 很多的垃圾邮件 都有不一般的标点符号规律 那么这是一个很强的特征 说明你应该 花费你的时间 去构造基于标点符号的 更加复杂的特征变量 因此 这种类型的误差分析 是一种手动检测的过程 检测算法可能会犯的错误 这经常能够帮助你 找到更为有效的手段 这也解释了为什么 我总是推荐先实践一种 快速即便不完美的算法 我们真正想要的是 找出什么类型的邮件 是这种算法最难分类出来的 对于不同的算法 不同的机器学习算法 它们 所遇到的问题一般总是相同的 通过实践一些快速 即便不完美的算法 你能够更快地 找到错误的所在 并且快速找出算法难以处理的例子 这样你就能集中精力在这些真正的问题上 最后 在构造机器学习算法时 另一个有用的小窍门是 保证你自己 保证你能有一种 数值计算的方式来评估你的机器学习算法 我这么说的意思是 如果你在构造一个学习算法 如果你能有一种 评估你算法的方法 这是非常有用的 一种用数字说话的评估方法 你的算法可能精确 可能有错 但是它能准确的告诉你你的算法到底表现有多好 在接下来的课程中 我会更详细的讲述这个概念 但是先看看这个例子 假设我们试图 决定是否应该 把像"discount""discounts""discounter""discountring" 这样的单词都视为等同 一种方法 是检查这些单词的 开头几个字母 比如 当你在检查这些单词开头几个字母的时候 你发现 这几个单词 大概可能有着相同的意思 在自然语言处理中 这种方法 是通过一种叫做词干提取的软件实现的 如果你想自己来试试 你可以 在网上搜索一下 "Porter Stemmer(波特词干提取法)" 这是在词干提取方面 一个比较不错的软件 这个软件会 将单词"discount""discounts"以及等等 都视为同一个单词 但是这种词干提取软件 只会检查 单词的头几个字母 这有用 但是也可能会造成一些问题 因为 举个例子 因为这个软件会把单词"universe(宇宙)" 和"university(大学)" 也视为同一个单词 因为 这两个单词开头的字母是一样的 因此 当你在决定 是否应该使用词干提取软件用来分类 这总是很难说清楚 特别地 误差分析 也并不能帮助你决定 词干提取是不是一个好的方法 与之相对地 最好的方法 来发现词干提取软件 对你的分类器 到底有没有用 是迅速地着手试一试 来看看它表现到底怎么样 为了这么做 通过数值来评估你的算法 是非常有用的 具体地说 自然而然地 你应该通过交叉验证 来验证不用词干提取与用词干提取的算法的错误率 因此 如果你不在你的算法中使用词干提取 然后你得到 比如 5%的分类错误率 然后你再使用词干提取来运行你的算法 你得到 比如 3%的分类错误 那么这很大的减少了错误发生 于是你决定 词干提取是一个好的办法 就这个特定的问题而言 这里有一个数量的评估数字 即交差验证错误率 我们以后会发现 这个例子中的评估数字 还需要一些处理 但是 我们可以在今后的课程中看到 这么做还是会让你 能更快地做出决定 比如 是否使用词干提取 再说一个例子 假设 你在想是否应该 区分单词的大小写 比如 单词"mom" 大写的"M" 和小写的"m" 它们应该被视作 同一个单词还是不同的单词 它们应该被视作相同的特征变量还是不同的 再说一次 因为我们有一种 能够评估我们算法的方法 如果你在这里试一试 如果我不区分 大小写 最后得到3.2%的错误率 然后我发现 这个表现的较差些 如果 如果我只用了词干提取 这之后我再思考 是否要区分 大小写 因此当你在 构造学习算法的时候 你总是会去尝试 很多新的想法 实现出很多版本的学习算法 如果每一次 你实践新想法的时候 你都手动地检测 这些例子 去看看是表现差还是表现好 那么这很难让你 做出决定 到底是否使用词干提取 是否区分大小写 但是通过一个 量化的数值评估 你可以看看这个数字 误差是变大还是变小了 你可以通过它 更快地实践 你的新想法 它基本上非常直观地告诉你 你的想法是提高了算法表现 还是让它变得更坏 这会大大提高 你实践算法时的速度 所以我强烈推荐 在交叉验证集上来实施误差分析 而不是在测试集上 但是 还是有一些人 会在测试集上来做误差分析 即使这从数学上讲 是不合适的 所以我还是推荐你 在交叉验证向量上 来做误差分析 总结一下 当你在研究一个新的机器学习问题时 我总是推荐你 实现一个较为简单快速 即便不是那么完美的算法 我几乎从未见过 人们这样做 大家经常干的事情是 花费大量的时间 在构造算法上 构造他们以为的简单的方法 因此 不要担心你的算法太简单 或者太不完美 而是尽可能快地 实现你的算法 当你有了初始的实现之后 它会变成一个非常有力的工具 来帮助你决定 下一步的做法 因为我们可以先看看算法造成的错误 通过误差分析 来看看他犯了什么错 然后来决定优化的方式 另一件事是 假设你有了一个快速而不完美的算法实现 又有一个数值的评估数据 这会帮助你 尝试新的想法 快速地发现 你尝试的这些想法 是否能够提高算法的表现 从而 你会更快地 做出决定 在算法中放弃什么 吸收什么
Handling Skewed Data
Error Metrics for Skewed Classes
在前面的课程中 我提到了误差分析 以及设定误差度量值的重要性 那就是 设定某个实数来评估你的学习算法 并衡量它的表现 有了算法的评估 和误差度量值 有一件重要的事情要注意 就是使用一个合适的误差度量值 这有时会对于你的学习算法 造成非常微妙的影响 这件重要的事情就是 偏斜类(skewed classes)的问题 让我告诉你这是什么意思 想一想之前的癌症分类问题 我们拥有 内科病人的特征变量 我们希望知道他们是否患有癌症 因此这就像恶性 与良性肿瘤的分类问题 我们之前讲过这个 我们假设 y=1 表示患者患有癌症 假设 y=0 表示他们没有得癌症 我们训练逻辑回归模型 假设我们用测试集 检验了这个分类模型 并且发现它只有1%的错误 因此我们99%会做出正确诊断 看起来是非常不错的结果 我们99%的情况都是正确的 但是 假如我们发现 在测试集中 只有0.5%的患者 真正得了癌症 因此 在我们的筛选程序里 只有0.5%的患者患了癌症 因此在这个例子中 1%的错误率就不再显得那么好了 举个具体的例子 这里有一行代码 不是机器学习代码 它忽略了输入值X 它让y总是等于0 因此它总是预测 没有人得癌症 那么这个算法实际上只有 0.5%的错误率 因此这甚至比 我们之前得到的1%的错误率更好 这是一个 非机器学习算法 因为它只是预测y总是等于0 这种情况发生在 正例和负例的比率 非常接近于 一个极端 在这个例子中 正样本的数量 与负样本的数量相比 非常非常少 因为y=1非常少 我们把这种情况叫做 偏斜类 一个类中的样本数 与另一个类的数据相比 多很多 通过总是预测y=0 或者 总是预测y=1 算法可能表现非常好 因此使用分类误差 或者分类精确度 来作为评估度量可能会产生如下问题 假如说你有一个算法 它的精确度是99.2% 因此它只有0.8%的误差 假设 你对你的算法做出了一点改动 现在你得到了 99.5%的精确度 只有0.5%的误差 这到底是不是算法的一个提升呢 用某个实数来 作为评估度量值 的一个好处就是 它可以帮助我们迅速决定 我们是否需要对算法做出一些改进 将精确度从99.2%提高到99.5% 但是我们的改进到底是有用的 还是说 我们只是把代码替换成了 例如总是预测y=0 这样的东西 因此如果你有一个偏斜类 用分类精确度 并不能很好地衡量算法 因为你可能会获得一个很高的精确度 非常低的错误率 但是我们并不知道 我们是否真的提升了 分类模型的质量 因为总是预测y=0 并不是一个 好的分类模型 但是总是预测y=0 会将你的误差降低至 比如 降低至0.5% 当我们遇到 这样一个偏斜类时 我们希望有一个 不同的误差度量值 或者不同的评估度量值 其中一种评估度量值 叫做查准率(precision)和召回率(recall) 让我来解释一下 假设我们正在用测试集来评估一个分类模型 对于 测试集中的样本 每个测试集中的样本 都会等于 0或者1 假设这是一个二分问题 我们的学习算法 要做的是 做出值的预测 并且学习算法 会为每一个 测试集中的实例 做出预测 预测值也是等于0或1 让我画一个 2x2的表格 基于所有这些值 基于 实际的类与预测的类 如果 有一个样本它实际所属的类是1 预测的类也是1 那么 我们把这个样本叫做真阳性(true positive) 意思是说我们的学习算法 预测这个值为阳性 实际上这个样本也确实是阳性 如果我们的学习算法 预测某个值是阴性 等于0 实际的类也确实属于0 那么我们把这个叫做真阴性(true negative) 我们预测为0的值实际上也等于0 还剩另外的两个单元格 如果我们的学习算法 预测某个值等于1 但是实际上它等于0 这个叫做假阳性(false positive) 比如我们的算法 预测某些病人患有癌症 但是事实上他们并没有得癌症 最后 这个单元格是 1和0 这个叫做假阴性(false negative) 因为我们的算法预测值为0 但是实际值是1 这样 我们有了一个2x2的表格 基于 实际类与预测类 这样我们有了一个 另一种方式来 评估算法的表现 我们要计算两个数字 第一个叫做查准率 这个意思是 对于所有我们预测 他们患有癌症的病人 有多大比率的病人是真正患有癌症的 让我把这个写下来 一个分类模型的查准率 等于 真阳性除以 所有我们预测为阳性 的数量 对于那些病人 我们告诉他们 "你们患有癌症" 对于这些病人而言 有多大比率是真正患有癌症的 这个就叫做查准率 另一个写法是 分子是真阳性 分母是 所有预测阳性的数量 那么这个等于 表格第一行的值 的和 也就是真阳性除以真阳性... 这里我把阳性简写为 POS 加上假阳性 这里我还是把阳性简写为POS 这个就叫做查准率 查准率越高就越好 这是说 对于那些病人 我们告诉他们 "非常抱歉 我们认为你得了癌症" 高查准率说明 对于这类病人 我们对预测他们得了癌症 有很高的准确率 另一个数字我们要计算的 叫做召回率 召回率是 如果所有的病人 假设测试集中的病人 或者交叉验证集中的 如果所有这些在数据集中的病人 确实得了癌症 有多大比率 我们正确预测他们得了癌症 如果所有的病人 都患了癌症 有多少人我们能够 正确告诉他们 你需要治疗 把这个写下来 召回率被定义为 真阳性 的数量 意思是我们正确预测 患有癌症的人 的数量 我们用这个来 除以 实际阳性 这个值是 所有患有癌症的人的数量 有多大比率 我们能正确发现癌症 并给予治疗 把这个以另一种形式 写下来 分母是 实际阳性的数量 表格第一列值的和 将这个以不同的形式写下来 那就是 真阳性除以 真阳性 加上 假阴性 同样地 召回率越高越好 通过计算查准率 和召回率 我们能更好的知道 分类模型到底好不好 具体地说 如果我们有一个算法 总是预测y=0 它总是预测 没有人患癌症 那么这个分类模型 召回率等于0 因为它不会有 真阳性 因此我们能会快发现 这个分类模型 总是预测y=0 它不是一个好的模型 总的来说 即使我们有一个 非常偏斜的类 算法也不能够 "欺骗"我们 仅仅通过预测 y总是等于0 或者y总是等于1 它没有办法得到 高的查准率 和高的召回率 因此我们 能够更肯定 拥有高查准率或者高召回率的模型 是一个好的分类模型 这给予了我们一个 更好的评估值 给予我们一种更直接的方法 来评估模型的好与坏 最后一件需要记住的事 在查准率和召回率的定义中 我们定义 查准率和召回率 我们总是习惯性地用y=1 如果这个类出现得非常少 因此如果我们试图检测 某种很稀少的情况 比如癌症 我希望它是个很稀少的情况 查准率和召回率 会被定义为 y=1 而不是y=0 作为某种我们希望检测的 出现较少的类 通过使用查准率和召回率 我们发现 即使我们拥有 非常偏斜的类 算法不能够 通过总是预测y=1 来"欺骗"我们 或者总是预测y=0 因为它不能够获得高查准率和召回率 具体地说 如果一个分类模型 拥有高查准率和召回率 那么 我们可以确信地说 这个算法表现很好 即便我们拥有很偏斜的类 因此对于偏斜类的问题 查准率和召回率 给予了我们更好的方法 来检测学习算法表现如何 这是一种 更好地评估学习算法的标准 当出现偏斜类时 比仅仅只用分类误差或者分类精度好
Trading Off Precision and Recall
在之前的课程中 我们谈到 查准率和召回率 作为遇到偏斜类问题 的评估度量值 在很多应用中 我们希望能够保证 查准率和召回率的相对平衡 在这节课中 我将告诉你应该怎么做 同时也向你展示一些 查准率和召回率 作为算法评估度量值的 更有效的方式 回忆一下 这是查准率和召回率的定义 我们在上一节中讲到的 让我们继续用 癌症分类的例子 如果病人患癌症 则y=1 反之则y=0 假设我们用 逻辑回归模型训练了数据 输出概率在0-1之间的值 因此 我们预测y=1 如果h(x) 大于或等于0.5 预测值为0 如果方程输出值 小于0.5 这个回归模型 能够计算查准率和召回率 但是现在 假如我们希望 在我们非常确信地情况下 才预测一个病人得了癌症 因为你知道 如果你告诉一个病人 告诉他们你得了癌症 他们会非常震惊 因为这是一个 非常坏的消息 而且他们会经历一段 非常痛苦的治疗过程 因此我们希望 只有在我们非常确信的情况下 才告诉这个人他得了癌症 这样做的一种方法 是修改算法 我们不再将临界值 设为0.5 也许 我们只在 h(x)的值大于或等于0.7 的情况下 才预测y=1 因此 我们会告诉一个人 他得了癌症 在我们认为 他有大于等于70%得癌症的概率情况下 如果你这么做 那么你只在 非常确信地情况下 才预测癌症 那么你的回归模型 会有较高的查准率 因为所有你准备 告诉他们 患有癌症的病人 所有这些人 有比较高的可能性 他们真的患有癌症 你预测患有癌症的病人中 有较大比率的人 他们确实患有癌症 因为这是我们 在非常确信的情况下做出的预测 与之相反 这个回归模型会有较低的召回率 因为 当我们做预测的时候 我们只给很小一部分的病人预测y=1 现在我们把这个情况夸大一下 我们不再把临界值 设在0.7 我们把它设为0.9 我们只在至少90%肯定 这个病人患有癌症的情况下 预测y=1 那么这些病人当中 有非常大的比率 真正患有癌症 因此这是一个高查准率的模型 但是召回率会变低 因为我们希望能够正确检测患有癌症的病人 现在考虑一个不同的例子 假设我们希望 避免遗漏掉患有癌症的人 即我们希望避免假阴性 具体地说 如果一个病人实际患有癌症 但是我们并没有告诉他患有癌症 那这可能造成严重后果 因为 如果我们告诉病人他们没有患癌症 那么 他们就不会接受治疗 但是如果 他们患有癌症 我们又没有告诉他们 那么他们就根本不会接受治疗 那么 这么可能造成严重后果 病人丧失生命 因为我们没有告诉他患有癌症 他没有接受治疗 但事实上他又患有癌症 这种i情况下 我们希望预测y=1 我们希望 预测病人患有癌症 这样 他们会做进一步的检测 然后接受治疗 以避免他们真的患有癌症 在这个例子中 我们不再设置高的临界值 我们会设置另一个值 将临界值 设得较低 比如0.3 这样做 我们认为 他们有大于30%的几率 患有癌症 我们以更加保守的方式 告诉他们患有癌症 因此他们能够接受治疗 在这种情况下 我们会有一个 较高召回率的模型 因为 确实患有癌症的病人 有很大一部分 被我们正确标记出来了 但是 我们会得到较低的查准率 因为 我们预测患有癌症的病人比例越大 那么就有较大比例的人其实没有患癌症 顺带一提 当我在给 别的学生讲这个的时候 令人惊讶的是 有的学生问 怎么可以从两面来看这个问题 为什么我总是 只想要高查准率或高召回率 但是这看起来可以使两边都提高 但是我希望 算法是正确的 更普遍的一个原则是 这取决于你想要什么 你想要高查准率 低召回率 还是高召回率 低查准率 你可以预测y=1 当h(x)大于某个临界值 因此 总的来说 对于大多数的回归模型 你得权衡查准率和召回率 当你改变 临界值的值时 我在这儿画了一个 临界值 你可以画出曲线 来权衡查准率 和召回率 这里的一个值 反应出一个较高的临界值 这个临界值可能等于0.99 我们假设 只在有大于99%的确信度的情况下 才预测y=1 至少 有99%的可能性 因此这个点反应高查准率 低召回率 然而这里的一个点 反映一个较低的临界值 比如说0.01 毫无疑问 在这里预测y=1 如果你这么做 你最后会得到 很低的查准率 但是较高的召回率 当你改变临界值 如果你愿意 你可以画出回归模型的所有曲线 来看看你能得到的查准率和召回率的范围 顺带一提 查准率-召回率曲线可以是各种不同的形状 有时它看起来是这样 有时是那样 查准率-召回率曲线的形状 有很多可能性 这取决于回归模型的具体算法 因此这又产生了 另一个有趣的问题 那就是 有没有办法自动选取临界值 或者 更广泛地说 如果我们有不同的算法 或者不同的想法 我们如何比较不同的查准率和召回率呢? 具体来说 假设我们有三个 不同的学习算法 或者这三个不同的学习曲线 是同样的算法 但是临界值不同 我们怎样决定哪一个算法是最好的 我们之前讲到的 其中一件事就是 评估度量值的重要性 这个概念是 通过一个具体的数字 来反映你的回归模型到底如何 但是查准率和召回率的问题 我们却不能这样做 因为在这里我们有两个可以判断的数字 因此 我们经常会 不得不面对这样的情况 如果我们正在试图比较算法1 和算法2 我们最后问自己 到底是0.5的查准率与 0.4的召回率好 还是说 0.7的查准率与 0.1的召回率好 或者每一次 你设计一个新算法 你都要坐下来思考 到底0.5 0.4好 还是说 0.7 0.1好 我不知道 如果你最后这样坐下来思考 这回降低 你的决策速度 思考到底哪些改变是有用的 应该被融入到你的算法 与此相反的是 如果我们有一个评估度量值 一个数字 能够告诉我们到底是算法1好还是算法2好 这能够帮助我们 更快地决定 哪一个算法更好 同时也能够更快地帮助我们 评估不同的改动 哪些应该被融入进算法里面 那么 我们怎样才能 得到这个评估度量值呢? 你可能会去尝试的 一件事情是 计算一下查准率和召回率的平均值 用 P 和 R 来表示查准率和召回率 你可以做的是 计算它们的平均值 看一看哪个模型有最高的均值 但是这可能 并不是一个很好的解决办法 因为 像我们之前的例子一样 如果我们的回归模型 总是预测 y=1 这么做你可能得到非常高的召回率 得到非常低的查准率 相反地 如果你的模型 总是预测y=0 就是说 如果很少预测y=1 对应的 设置了一个高临界值 最后 你会得到非常高的 查准率和非常低的召回率 这两个极端情况 一个有非常高的临界值 一个有非常低的临界值 它们中的任何一个都不是一个好的模型 我们可以通过 非常低的查准率 或者非常低的召回率 判断这不是一个好模型 如果你只是使用(P+R)/2 算法3的这个值 是最高的 即使你可以通过 使用总是预测y=1这样的方法 来得到这样的值 但这并不是一个好的模型 对吧 你总是预测y=1 这不是一个有用的模型 因为它只输出y=1 那么算法1和 算法2 比算法3更有用 但是在这个例子中 查准率和召回率的平均值 算法3是最高的 因此我们通常认为 查准率和召回率的平均值 不是评估算法的一个好的方法 相反地 有一种结合查准率和召回率的不同方式 叫做F值 公式是这样 在这个例子中 F值是这样的 我们可以通过 F值来判断 算法1 有最高的F值 算法2第二 算法3是最低的 因此 通过F值 我们会在这几个算法中选择算法1 F值 也叫做F1值 一般写作F1值 但是人们一般只说F值 它的定义 会考虑一部分 查准率和召回率的平均值 但是它 会给查准率和召回率中较低的值 更高的权重 因此 你可以看到F值的分子 是查准率和召回率的乘积 因此如果查准率等于0 或者召回率等于0 F值也会 等于0 因此它结合了查准率和召回率 对于一个较大的F值 查准率 和召回率都必须较大 我必须说 有较多的公式 可以结合查准率和召回率 F值公式 只是 其中一个 但是出于历史原因 和习惯问题 人们在机器学习中使用F值 这个术语F值 没有什么特别的意义 所以不要担心 它到底为什么叫做F值或者F1值 但是它给了你 你需要的有效方法 因为无论是查准率等于0 还是召回率等于0 它都会得到一个很低的F值 因此 如果要得到一个很高的F值 你的算法的查准率和召回率都要接近于1 具体地说 如果P=0或者 R=0 你的F值也会等于0 对于一个最完美的F值 如果查准率等于1 同时召回率 也等于1 那你得到的F值 等于1乘以1 除以2再乘以2 那么F值 就等于1 如果你能得到最完美的查准率和召回率 在0和1中间的值 这经常是 回归模型最经常出现的分数 在这次的视频中 我们讲到了如何 权衡查准率和召回率 以及我们如何变动 临界值 来决定我们希望预测y=1 还是y=0 比如我们 需要一个 70%还是90%置信度的临界值 或者别的 来预测y=1 通过变动临界值 你可以控制权衡 查准率和召回率 之后我们讲到了F值 它权衡查准率和召回率 给了你一个 评估度量值 当然 如果你的目标是 自动选择临界值 来决定 你希望预测y=1 还是y=0 那么一个比较理想的办法是 试一试不同的 临界值 试一下 不同的临界值 然后评估这些不同的临界值 在交叉检验集上进行测试 然后选择哪一个临界值 能够在交叉检验集上 得到最高的F值 这是自动选择临界值的较好办法 较好办法
Using Large Data Sets
Data For Machine Learning
在之前的视频中 我们讨论了评价指标 在本节课的视频中 我要稍微转换一下 讨论一下机器学习系统设计中 另一个重要的方面 这往往涉及到 用来训练的数据 有多少 在之前的一些视频中 我曾告诫大家不要盲目地开始 而是花大量的时间 来收集大量的数据 因为数据 有时是唯一能实际起到作用的 但事实证明 在一定条件下 我会在这个视频里讲到 这些条件是什么 得到大量的数据并在 某种类型的学习算法中进行训练 可以是一种 有效的方法来获得 一个具有良好性能的学习算法 而这种情况往往出现在 这些条件对于你的问题 都成立 并且 你能够得到大量数据的 情况下 这可以是 一个很好的方式来获得 非常高性能的学习算法 因此 在这段视频中 让我们一起讨论一下这个问题 我先讲一个故事 很多很多年前 我认识的两位研究人员 Michele Banko 和 Eric Brill 进行了一项有趣的研究 他们感兴趣的是研究 使用不同的学习算法的效果 与将这些效果 使用到不同训练数据集上 两者的比较 他们当时考虑这样一个问题 如何在易混淆的词之间进行分类 比如 在这样的句子中: 早餐我吃了__个鸡蛋 (to,two,too) 在这个例子中 早餐我吃了2个鸡蛋 这是一个 易混淆的单词的例子 而这是另外一组情况 于是他们把诸如这样的机器学习问题 当做一类监督学习问题 并尝试将其分类 什么样的词 在一个英文句子特定的位置 才是合适的 他们用了几种不同的学习算法 这些算法都是 在他们2001年进行研究的时候 都已经 被公认是比较领先的 因此他们使用了一个方差 用于逻辑回归上的一个方差 被称作"感知器" (perceptron) 他们也采取了一些 过去常用 但是现在比较少用的算法 比如 Winnow 算法 很类似于 回归问题 但在一些方面又有所不同 过去用得比较多 但现在用得不太多 还有一种基于内存的学习算法 现在也用得比较少了 但是我稍后会讨论一点 而且他们用了一个朴素算法 这个我们将在 这门课程中讨论到 这些具体算法的细节不那么重要 想象一下 就是选了四种分类算法 这些具体算法并不重要 他们所做的就是 改变了训练数据集的大小 并尝试将这些学习算法 用于不同大小的 训练数据集中 这就是他们得到的结果 这些趋势非常明显 首先大部分算法 都具有相似的性能 其次 随着训练 数据集的增大 在横轴上代表 以百万为单位的 训练集大小 从0.1个百万到1000百万 也就是到了 10亿规模的训练集的样本 这些算法的性能 也都对应地增强了 事实上 如果 你选择任意一个算法 可能是 选择了一个"劣等的"算法 如果你给这个 劣等算法更多的数据 那么 从这些列子中看起来的话 它看上去 很有可能会其他算法更好 甚至会比"优等算法"更好 由于这项原始的研究 非常具有影响力 因此已经有 一系列许多不同的 研究显示了类似的结果 这些结果表明 许多不同的 学习算法有时倾向于 表现出非常相似的表现 这还取决于一些细节 但是真正能提高性能的 是你能够给一个算法大量的训练数据 像这样的结果 引起了一种 在机器学习中 的普遍共识: "取得成功的人不是拥有最好算法的人 而是拥有最多数据的人" 那么这种说法 在什么时候是真 什么时候是假呢? 因为如果我们有一个学习算法 并且如果这种说法是真的 那么得到大量 的数据通常是 保证我们 具有一个高性能算法 的最佳方式 而不是 去争辩应该用什么样的算法 假如有这样一些假设 在这些假设下有 大量我们认为有用的训练集 我们假设在我们的 机器学习问题中 特征值 x 包含了足够的信息 这些信息可以帮助我们用来准确地预测 y 例如 如果我们采用了 我们前一张幻灯片里的所有容易混淆的词 假如说它能够描述 x 捕捉到需要填写 的空白处周围的词语 那么特征捕捉到之后 我们就希望有 对于“早饭我吃了__鸡蛋” 那么这就有 大量的信息来告诉我 中间我需要填的 词是“两个” (two) 而不是单词 to 或 too 因此特征捕捉 哪怕是周围词语中的一个词 就能够给我足够的 信息来确定出 标签 y 是什么 换句话说 从这三组易混淆的词中 我应该选什么 词来填空 这就是一个例子 特征值 x 有充足的信息 来确定 y 举一个反例 设想一个 房子价格的问题 房子只有大小信息 没有其他特征 那么 如果我告诉你 这个房子有 500平方英尺 但是我没有告诉你其他的特征信息 我也不告诉你这个 房子位于这个城市房价比较昂贵的区域 如果我也不告诉你 这所房子的 房间数量 或者 它里面陈设了多漂亮的家具 或这个房子是新的还是旧的 我不告诉你其他任何信息 除了这个房子 有500平方英尺以外 然而除此之外还有许多其他因素 会影响房子的价格 不仅仅是房子的大小 如果所有 你所知道的只有房子的尺寸 那么事实上 是很难准确预测它的价格的 这是对于这个假设 的一个反例 假设是特征能够提供足够的信息 来在需要的水平上预测出价格 我经常思考 如果我想测试这样一个 假设的方式是什么 我经常这样问自己: 给定一个输入特征向量 x 给定这些特征值 也给定了相同的可用的信息和学习算法 如果我们去请教这个领域的人类专家 一个人类专家能够 准确或自信地预测出 y 的值吗? 第一个例子 如果我们去 找你认识的一个英语专家 比如你找到了一个 英语说得很好的人 那么 一个英语方面的专家 大部分像 你和我这样的人 我们可能不难 预测出在这种情况下 该使用什么样的语言 一个英语说得好的人 应该可以预测得很好 因此这就给了我信心 x能够让我们 准确地预测y 但是与此相反 如果我们去找一个价格上的专家 比如 可能是一个房地产经纪人 或者职业售楼小姐 如果我只是告诉他们 一个房子的大小 然后问他们房子的价格 那么即使是擅长房价评估 或者售房方面的专家 也不能告诉我 房子的价格是多少 所以在房价的例子中 只知道房子的大小并不能 给我足够的信息来预测 房子的价格 如果这个假设是成立的 那么让我们来看一看 大量的数据是有帮助的情况 假设特征值有 足够的信息 来预测 y 值 假设我们使用一种 需要大量参数的 学习算法 比如有很多特征的 逻辑回归或线性回归 或者我有时做的一件事 我经常做的一件事 就是用带有许多隐藏单元的神经网络 那又是另外一种 带有很多参数的学习算法了 这些都是非常强大的学习算法 它们有很多参数 这些参数可以拟合非常复杂的函数 因此我要调用这些 我将把这些算法想象成 低偏差算法 因为 我们能够拟合非常复杂的函数 而且因为我们有 非常强大的学习算法 这些学习算法能够拟合非常复杂的函数 很有可能 如果我们 用这些数据运行 这些算法 这种算法能 很好地拟合训练集 因此 训练误差就会很低 现在假设我们使用了 非常非常大的训练集 在这种情况下 如果我们 有一个庞大的训练集 那么 尽管我们希望有很多参数 但是如果训练集比 比参数的数量还大 甚至是更多 那么这些 算法就不太可能会过度拟合 因为我们有如此 庞大的训练集 并且不太可能过度拟合 也就是说训练 误差有希望 接近测试误差 最后把这两个 放在一起 训练集 误差很小 而 测试集误差又接近 训练误差 这两个就意味着 测试集的误差 也会很小 另一种考虑 这个问题的角度是 为了有一个高 性能的学习算法 我们希望 它不要有高的偏差和方差 因此偏差问题 我么将 通过确保 有一个具有很多 参数的学习算法来解决 以便 我们能够得到一个较低偏差的算法 并且通过用 非常大的训练集来保证 我们在此没有方差问题 我们的算法将 没有方差 并且 通过将这两个值放在一起 我们最终可以得到一个低 误差和低方差 的学习算法 这 使得我们能够 很好地测试测试数据集 从根本上来说 这是一个关键 的假设:特征值 有足够的信息量 且我们 有一类很好的函数 这是为什么能保证低误差的关键所在 它有大量的 训练数据集 这能保证得到更多的方差值 因此这给我们提出了 一些可能的条件 一些对于 问题的认识 如果 你有大量的数据 而且你训练了一种 带有很多参数的学习算法 那么这将 会是一个很好的方式来提供 一个高性能的学习算法 我觉得关键的测试 我常常问自己 首先 一个人类专家 看到了特征值 x 能很有信心的预测出 y值吗? 因为这可以 证明 y 可以根据特征值 x 被准确地预测出来 其次 我们实际上能得到一组 庞大的训练集并且在这个 训练集中训练一个有 很多参数的学习算法吗? 如果你不能做到这两者 那么更多时候 你会得到一个性能很好的学习算法
Machine Learning - 第6周(Advice for Applying Machine Learning、Machine Learning System Design)的更多相关文章
- Advice for applying Machine Learning
https://jmetzen.github.io/2015-01-29/ml_advice.html Advice for applying Machine Learning This post i ...
- 斯坦福大学公开课机器学习:advice for applying machine learning | diagnosing bias vs. variance(机器学习:诊断偏差和方差问题)
当我们运行一个学习算法时,如果这个算法的表现不理想,那么有两种原因导致:要么偏差比较大.要么方差比较大.换句话说,要么是欠拟合.要么是过拟合.那么这两种情况,哪个和偏差有关.哪个和方差有关,或者是不是 ...
- 【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 10—Advice for applying machine learning 机器学习应用建议
Lecture 10—Advice for applying machine learning 10.1 如何调试一个机器学习算法? 有多种方案: 1.获得更多训练数据:2.尝试更少特征:3.尝试更多 ...
- (原创)Stanford Machine Learning (by Andrew NG) --- (week 6) Advice for Applying Machine Learning & Machine Learning System Design
(1) Advice for applying machine learning Deciding what to try next 现在我们已学习了线性回归.逻辑回归.神经网络等机器学习算法,接下来 ...
- Coursera 机器学习 第6章(上) Advice for Applying Machine Learning 学习笔记
这章的内容对于设计分析假设性能有很大的帮助,如果运用的好,将会节省实验者大量时间. Machine Learning System Design6.1 Evaluating a Learning Al ...
- Stanford机器学习笔记-7. Machine Learning System Design
7 Machine Learning System Design Content 7 Machine Learning System Design 7.1 Prioritizing What to W ...
- Machine Learning - XI. Machine Learning System Design机器学习系统的设计(Week 6)
http://blog.csdn.net/pipisorry/article/details/44119187 机器学习Machine Learning - Andrew NG courses学习笔记 ...
- 对deep learning的第一周调研
下面仅是我的个人认识,说得不正确请轻拍. (眼下,我仅仅看了一些deep learning 的review和TOM Mitchell的书<machine learning>中的神经网络一章 ...
- 【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 11—Machine Learning System Design 机器学习系统设计
Lecture 11—Machine Learning System Design 11.1 垃圾邮件分类 本章中用一个实际例子: 垃圾邮件Spam的分类 来描述机器学习系统设计方法.首先来看两封邮件 ...
随机推荐
- PHP CURL实现远程下载文件到本地
<?php //$result=httpcopy('http://www.phpernote.com/image/logo.gif'); echo '<pre>';print_r($ ...
- samba共享服务器搭建 亲手实验
一.简介 Samba是一个能让Linux系统应用Microsoft网络通讯协议的软件,而SMB是Server Message Block的缩写,即为服务器消息块 ,SMB主要是作为Microsoft的 ...
- Java动态代理 cglib
代理模式:为某些对象提供代理以实现对这个对象的访问. 对一个对象进行访问控制的原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化. 一般包括以下组件: 被代理者接口:提供被代理者的访问途径. ...
- VC++ 使用WebBrowser控件中html文件以资源形式加载
. . . . //加载资源文件中的HTML,IDR_HTML1就是HTML文件在资源文件中的ID wchar_t self_path[MAX_PATH] = { }; GetModuleFileNa ...
- WinCE开机Logo的实现(USB下载图片到nandflash)
WinCE开机启动Logo使用Eboot读取NandFlash中的图片数据,然后显示的方式.对于开机logo的方式网友http://jazka.blog.51cto.com/809003/664131 ...
- ORACLE分页SQL语句
.根据ROWID来分 select * from t_xiaoxi where rowid in(select rid from (select rownum rn,rid from(select r ...
- 注册dll失败
注册DLL的时候一出现错误: win8下: (右键弹出) 如果再不行, 64位系统下,把DLL移动到C:\Windows\SysWOW64下 更改路径
- MySQL(七) —— MySQL存储过程 & 存储引擎
MySQL中输入语句的执行过程: 如果我们可以将上面的过程简化,吧语法分析或者编译等步骤简化,则可以将整个流程简化. 存储过程: 是SQL语句和控制语句的预编译集合,以一个名称存储并作为一个单元处理: ...
- Typescript的面向对象
封装: var Greeter = (function () { function Greeter(message) { this.greeting = message; } Greeter.prot ...
- js文件的装载和执行
1.浏览器对script引用的js文件分两步,下载,下载完毕后马上执行:这两步都会阻塞浏览器继续解析. 2.加入defer属性,<script defer type="text/jav ...