提交 ef5b5668 编写于 作者: W wizardforcel

边界框 => 边框

上级 e53c9e9c
......@@ -8,9 +8,9 @@
* 许多学生正在努力学习上周的材料,所以如果你觉得很难,那很好。杰里米预先把它放在那里的是因为我们有一些东西要不断思考,并慢慢努力,所以在第14课,你将得到第二个飞跃。
* 要理解这些碎片,你需要理解卷积层输出、感受野和损失函数的维度 - 无论如何,这些都是你所有需要了解的深度学习研究的内容。
* 一个关键的问题是我们从简单的东西开始 - 单个对象分类器,没有分类器的单个对象边界框,然后是单个对象分类器和边界框。 除了首先我们必须解决匹配问题之外,我们迁移到多个对象上实际几乎相同。 我们最终创建了比我们的基础真实边界框所需的激活更多的激活数量,因此我们将每个地面实况对象与这些激活的子集相匹配。 一旦我们完成了这个,我们对每个匹配所做的损失函数几乎与这个损失函数(即单个对象分类器和边界框的损失函数)相同。
* 一个关键的问题是我们从简单的东西开始 - 单个对象分类器,没有分类器的单个对象边框,然后是单个对象分类器和边框。 除了首先我们必须解决匹配问题之外,我们迁移到多个对象上实际几乎相同。 我们最终创建了比我们的基础真实边框所需的激活更多的激活数量,因此我们将每个地面实况对象与这些激活的子集相匹配。 一旦我们完成了这个,我们对每个匹配所做的损失函数几乎与这个损失函数(即单个对象分类器和边框的损失函数)相同。
* 如果你感觉困难,请返回第8课,确保你了解了数据集,DataLoader,最重要的是了解损失函数。
* 因此,一旦我们有了可以预测一个对象的类和边框的东西,我们通过创建更多的激活来进入多个对象 [[2:40](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D2m40s)] 。 之后,我们必须处理匹配问题,处理了一个匹配问题之后,我们将每个锚箱移入移出一点,再移到周围一点,所以他们试图与特定的地面实例对象进行对齐。
* 因此,一旦我们有了可以预测一个对象的类和边框的东西,我们通过创建更多的激活来进入多个对象 [[2:40](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D2m40s)] 。 之后,我们必须处理匹配问题,处理了一个匹配问题之后,我们将每个锚箱移入移出一点,再移到周围一点,所以他们试图与特定的地面实例对象进行对齐。
* 我们谈到了我们如何利用网络的卷积性质来尝试激活具有与我们所预测的基本事实对象类似的接受场。 Chloe提供了以下奇妙的图片来讨论什么是SSD_MultiHead.forward,一行一行地看:
![](../img/1_BbxbH3gWu8RHMTuXZlDasA.png)
......@@ -24,7 +24,7 @@ Chloe在这里所做的是她特别关注路径中每个点处张量的维数,
![](../img/1_gwvD-lSxiUH_EFq9n-ofOQ.png)
* 这是你必须记住这个`pbd.set_trace()`的地方 。 我刚刚上课前进入`SSD_MultiHead.forward`并输入了`pdb.set_trace()`,然后运行了一个批处理。 之后我可以打印出所有这些的大小。我们可能有错误,这就是为什么我们有调试器并知道如何检查过程中的一些很小的问题。
* 然后我们讨论了增加_k_ [[5:49](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D5m49s)] ,这是每个卷积网格单元的锚箱数量,我们可以用不同的缩放比、宽高比进行处理,这给我们提供了大量的激活,因此预测了边框。
* 然后我们讨论了增加_k_ [[5:49](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D5m49s)] ,这是每个卷积网格单元的锚箱数量,我们可以用不同的缩放比、宽高比进行处理,这给我们提供了大量的激活,因此预测了边框。
* 然后我们使用非最大抑制来减小数值。
* 非最大抑制是一种粗糙的、丑陋的和完全的启发式,我们甚至没有讨论代码,因为它看起来很可怕。 最近有人提出了一篇论文,试图用一个端到端的卷积网来取代那个NMS( [https://arxiv.org/abs/1705.02950](https://arxiv.org/abs/1705.02950) )。
......@@ -71,7 +71,7 @@ Chloe在这里所做的是她特别关注路径中每个点处张量的维数,
* 今天,我们将看看同样的想法,看看它如何适用于NLP。
* 在下一课中,我们将进一步说明NLP和计算机视觉是否可以让你实现同样的基本想法,我们如何将两者结合起来。 实际上,我们将学习一个可以学习从图像中找到单词结构,从单词结构中找到图像或从图像中找到图像的模型。 如果你想进一步做一些事情,比如从一个图像到一个句子(即图像字幕),或者从一个句子到一个我们开始做的图像,一个短语到图像,那上面内容将构成基础。
* 从那里之后,我们必须更深入地进入计算机视觉,思考我们可以用预训练的网络和定制头的想法做些什么。 因此,我们将研究各种图像增强,例如增加低分辨率照片的分辨率以猜测缺少的内容或在照片上添加艺术滤镜,或将马的照片更改为斑马照片等。
* 最后,这将再次带我们回到边界框。为了达到这个目的,我们首先要学习分割,这不仅仅是找出边界框的位置,而是要弄清楚图像中每个像素的一部分 - 所以这个像素是一个人的一部分,这个像素是一辆车的一部分。 然后我们将用这个想法,特别是一个名为UNet的想法,结果证明了这个UNet的想法可以应用于边界框 - 它被称为特征金字塔。 我们将使用它来获得非常好的带有边界框的结果。这是我们从这里开始的路。 这一切都将建立在彼此的基础上,但将我们带入许多不同的领域。
* 最后,这将再次带我们回到边框。为了达到这个目的,我们首先要学习分割,这不仅仅是找出边框的位置,而是要弄清楚图像中每个像素的一部分 - 所以这个像素是一个人的一部分,这个像素是一辆车的一部分。 然后我们将用这个想法,特别是一个名为UNet的想法,结果证明了这个UNet的想法可以应用于边框 - 它被称为特征金字塔。 我们将使用它来获得非常好的带有边框的结果。这是我们从这里开始的路。 这一切都将建立在彼此的基础上,但将我们带入许多不同的领域。
#### torchtext to fastai.text [[18:56](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D18m56s)] :
......@@ -694,7 +694,7 @@ epoch trn_loss val_loss accuracy
[3.9084756, 0.3115861900150776]
```
**问题** :你在一周 [[1:25:24]( data-href=)] 的纸质阅读与敲代码的比例是多少? 天哪,你觉得怎么样,雷切尔? 你看我。 我的意思是,结果显示更多时间是在敲代码,对吗? “更多时间在敲代码。 我觉得每周也真的不一样“(瑞秋)。 有了这些边框的东西,有所有这些文件,没有通过它们的地图,所以我甚至不知道首先阅读哪一个,然后我读了引用,并且不理解它们中的任何一个。 所以在我甚至不知道如何开始敲代码之前,还有几周的阅读文章。 这是不寻常的。 每当我开始阅读一篇论文时,我总是相信,我不够聪明去理解它,无论论文是什么。 不知怎的,我最终做到了。 但我试着花费尽可能多的时间来敲代码。
**问题** :你在一周 [[1:25:24]( data-href=)] 的纸质阅读与敲代码的比例是多少? 天哪,你觉得怎么样,雷切尔? 你看我。 我的意思是,结果显示更多时间是在敲代码,对吗? “更多时间在敲代码。 我觉得每周也真的不一样“(瑞秋)。 有了这些边框的东西,有所有这些文件,没有通过它们的地图,所以我甚至不知道首先阅读哪一个,然后我读了引用,并且不理解它们中的任何一个。 所以在我甚至不知道如何开始敲代码之前,还有几周的阅读文章。 这是不寻常的。 每当我开始阅读一篇论文时,我总是相信,我不够聪明去理解它,无论论文是什么。 不知怎的,我最终做到了。 但我试着花费尽可能多的时间来敲代码。
几乎总是在我读完一篇论文 [[1:26:34]( data-href=)] 之后,即使在我读到这个问题之后,我正试图解决这个问题,我会停在那里尝试实现一些我认为可能会解决这个问题的想法。 然后我会回去阅读论文,我读到了关于这些问题的一些内容,我将如何解决这些问题,我会像“哦,这是一个好主意”,然后我会尝试实现这些。 这就是为什么,例如,实际上我没有实现SSD。 我的定制头与他们的头不一样。 这是因为我有点读了它的要点,然后我尽力创造出最好的东西,然后回到论文中,试着看看为什么。 所以当我到达焦点丢失纸时,雷切尔会告诉你,我为什么不能找到小物体而疯狂? 怎么总是预测背景? 我读了焦点丢失文件,我就像“这就是为什么!!”当你深刻理解他们试图解决的问题时,会好得多。 我确实找到绝大多数时间,当我读到解决问题的那篇文章的时候,我就像“是的,但是我想出了这三个想法,他们没有尝试。”然后你突然意识到你有新的想法。 或者,如果你只是盲目地实施论文,那么你往往没有更好的方法去做这些见解。
......
......@@ -58,7 +58,7 @@
PATH = Path('data/translate') TMP_PATH = PATH/'tmp' TMP_PATH.mkdir(exist_ok= **True** ) fname='giga-fren.release2.fixed' en_fname = PATH/f' **{fname}** .en' fr_fname = PATH/f' **{fname}** .fr'
```
对于边框,所有有趣的东西都在损失函数中,但对于神经翻译,所有有趣的东西都将在他的体系结构中 [[13:01](https://youtu.be/tY0n9OT5_nA%3Ft%3D13m1s)] 。 让我们快速完成这一切,杰里米希望你特别考虑的事情之一就是我们正在做的任务以及我们如何在语言建模与神经翻译之间做到这一点的关系或相似之处。
对于边框,所有有趣的东西都在损失函数中,但对于神经翻译,所有有趣的东西都将在他的体系结构中 [[13:01](https://youtu.be/tY0n9OT5_nA%3Ft%3D13m1s)] 。 让我们快速完成这一切,杰里米希望你特别考虑的事情之一就是我们正在做的任务以及我们如何在语言建模与神经翻译之间做到这一点的关系或相似之处。
![](../img/1_458KhA7uSET5eH3fe4EhDw.png)
......
......@@ -612,7 +612,7 @@ GAN的基本思想是它是一个生成模型 [[51:23](https://youtu.be/ondivPiw
* 识别斑马的GAN损失
* 我们两台发电机的循环一致性损失
我们在这里有一个lambda,希望我们已经习惯了这个想法,现在就是当你有两种不同的损失时,你可以将参数放在那里,你可以将它们相乘,所以它们的大小相同 [[1:59: 23](https://youtu.be/ondivPiwQho%3Ft%3D1h59m23s)] 。当我们进行本地化时,与分类器丢失相比,我们的边框丢失做了类似的事情。
我们在这里有一个lambda,希望我们已经习惯了这个想法,现在就是当你有两种不同的损失时,你可以将参数放在那里,你可以将它们相乘,所以它们的大小相同 [[1:59: 23](https://youtu.be/ondivPiwQho%3Ft%3D1h59m23s)] 。当我们进行本地化时,与分类器丢失相比,我们的边框丢失做了类似的事情。
然后,对于这种损失函数,我们将尝试最大化鉴别器区分的能力,同时最小化发生器的能力。因此,发电机和鉴别器将相互对立。当你在论文中看到这个_最小的_东西时,它基本上意味着这个想法,在你的训练循环中,有一件事是试图让事情变得更好,另一件事是试图让事情变得更糟,并且有很多方法可以做到但是最常见的是,你会在两者之间交替。你会经常看到这在数学论文中被称为min-max。因此,当你看到min-max时,你应该立即考虑**对抗训练**
......
......@@ -124,7 +124,7 @@ Alena Harley做了一些非常有趣的事情,她试图找出如果你只用
img_fn = PATH/'train'/'n01558993'/'n01558993_9684.JPEG'
```
我们需要做的下一件事是按照惯例创建我们的转换 [[18:13](https://youtu.be/nG3tT31nPmQ%3Ft%3D18m13s)] 。 我们将使用`tfm_y`参数,就像我们对边框所做的那样,而不是使用`TfmType.COORD`我们将使用`TfmType.PIXEL` 。 这告诉我们的转换框架你的_y_值是包含普通像素的图像,所以你对_x_做的任何事情,你也需要对_y_做同样的事情。 你需要确保你使用的任何数据增强转换都具有相同的参数。
我们需要做的下一件事是按照惯例创建我们的转换 [[18:13](https://youtu.be/nG3tT31nPmQ%3Ft%3D18m13s)] 。 我们将使用`tfm_y`参数,就像我们对边框所做的那样,而不是使用`TfmType.COORD`我们将使用`TfmType.PIXEL` 。 这告诉我们的转换框架你的_y_值是包含普通像素的图像,所以你对_x_做的任何事情,你也需要对_y_做同样的事情。 你需要确保你使用的任何数据增强转换都具有相同的参数。
```
tfms = tfms_from_model(arch, sz_lr, tfm_y=TfmType.PIXEL, aug_tfms=aug_tfms, sz_y=sz_hr) datasets = ImageData.get_ds(MatchedFilesDataset, (trn_x,trn_y), (val_x,val_y), tfms, path=PATH_TRN) md = ImageData(PATH, datasets, bs, num_workers=16, classes= **None** )
......@@ -1022,7 +1022,7 @@ _,axes = plt.subplots(1,2,figsize =(14,7))show_img(x [ None ],0
最后,我们来谈谈细分。这来自着名的CamVid数据集,它是学术分割数据集的典型示例。基本上你可以看到我们做的是我们从图片开始(它们实际上是这个数据集中的视频帧),我们有一些标签,它们实际上不是颜色 - 每个标签都有一个ID,ID被映射到颜色。所以红色可能是1,紫色可能是2,浅粉红色可能是3,所以所有的建筑都是一类,所有的汽车都是另一类,所有人都是另一类,所有的道路都是另一类,等等。所以我们在这里实际做的是每个像素的多类分类。你可以看到,有时候这种多类分类真的很棘手 - 就像这些分支一样。虽然,有时标签真的不那么好。你可以看到,这非常粗糙。这就是我们要做的事情。
我们将进行分割,因此它很像边框。但是,我们实际上要用它的类来标记每个像素,而不仅仅是在每个东西周围找到一个方框。实际上,它实际上要容易得多,因为它非常适合我们的CNN样式,我们可以创建任何CNN,其中输出是N×M网格,包含从0到C的整数,其中有C类。然后我们可以使用softmax激活的交叉熵损失,我们就完成了。我实际上可以在那里停止课程,你可以使用你在第1课和第2课中学到的完全相同的方法,你会得到一个非常好的结果。所以首先要说的是,这实际上并不是一件非常艰难的事情。但我们会尽力做到这一点。
我们将进行分割,因此它很像边框。但是,我们实际上要用它的类来标记每个像素,而不仅仅是在每个东西周围找到一个方框。实际上,它实际上要容易得多,因为它非常适合我们的CNN样式,我们可以创建任何CNN,其中输出是N×M网格,包含从0到C的整数,其中有C类。然后我们可以使用softmax激活的交叉熵损失,我们就完成了。我实际上可以在那里停止课程,你可以使用你在第1课和第2课中学到的完全相同的方法,你会得到一个非常好的结果。所以首先要说的是,这实际上并不是一件非常艰难的事情。但我们会尽力做到这一点。
#### 这样简单 [[1:31:26](https://youtu.be/nG3tT31nPmQ%3Ft%3D1h31m26s)]
......@@ -1842,7 +1842,7 @@ TRAIN_DN = 'train' MASKS_DN = 'train_masks_png' sz = 128 bs = 64 nw = 16
让我们试试U-Net吧。 我称之为U-net(ish),因为按照惯例,我正在创建我自己的有点hacky版本 - 尝试保持与你习惯的类似的东西,并做我觉得有意义的事情。 所以你应该有足够的机会通过查看确切的网格大小来至少使这个更真实的U-net,并看看这里(左上方的转换)大小是如何下降的。 所以他们显然没有添加任何填充,然后有一些裁剪正在进行 - 有一些差异。 但有一件事是因为我想利用转移学习 - 这意味着我不能完全使用U-Net。
所以这是另一个重要的机会,如果你创建U-Net下行路径然后在末尾添加分类器然后在ImageNet上训练它。 你现在已经拥有了ImageNet训练分类器,专门设计为U-Net的良好骨干。 那么你现在应该能够回来并且非常接近赢得这场旧比赛(实际上并不是那么久 - 这是最近的比赛)。 因为之前没有预先训练好的网络。 但是如果你想想YOLO v3做了什么,基本上就是这样。 他们创建了一个DarkNet,他们在ImageNet上预先训练了它,然后他们用它作为边框的基础。 同样,这种预先训练的想法不仅仅是为了分类而是为其他事物而设计 - 这只是没有人做过的事情。 但正如我们所展示的那样,你现在可以在三小时内以25美元的价格训练ImageNet。 如果社区中的人有兴趣这样做,希望我能得到你可以帮助你的学分,所以如果你这样做,设置它的工作并给我一个脚本,我可以为你运行它。 但就目前而言,我们还没有。 所以我们将使用ResNet。
所以这是另一个重要的机会,如果你创建U-Net下行路径然后在末尾添加分类器然后在ImageNet上训练它。 你现在已经拥有了ImageNet训练分类器,专门设计为U-Net的良好骨干。 那么你现在应该能够回来并且非常接近赢得这场旧比赛(实际上并不是那么久 - 这是最近的比赛)。 因为之前没有预先训练好的网络。 但是如果你想想YOLO v3做了什么,基本上就是这样。 他们创建了一个DarkNet,他们在ImageNet上预先训练了它,然后他们用它作为边框的基础。 同样,这种预先训练的想法不仅仅是为了分类而是为其他事物而设计 - 这只是没有人做过的事情。 但正如我们所展示的那样,你现在可以在三小时内以25美元的价格训练ImageNet。 如果社区中的人有兴趣这样做,希望我能得到你可以帮助你的学分,所以如果你这样做,设置它的工作并给我一个脚本,我可以为你运行它。 但就目前而言,我们还没有。 所以我们将使用ResNet。
```
**class** **SaveFeatures** (): features= **None** **def** __init__(self, m): self.hook = m.register_forward_hook(self.hook_fn) **def** hook_fn(self, module, input, output): self.features = output **def** remove(self): self.hook.remove()
......@@ -2218,9 +2218,9 @@ TRAIN_DN = 'train' MASKS_DN = 'train_masks_png' sz = 128 bs = 64 nw = 16
![](../img/1_1eNTc9dNtmuxTryHf1XGpA.png)
### 回到边框 [[1:58:15](https://youtu.be/nG3tT31nPmQ%3Ft%3D1h58m15s)]
### 回到边框 [[1:58:15](https://youtu.be/nG3tT31nPmQ%3Ft%3D1h58m15s)]
好的,就是这样。 我想提到的最后一件事现在是回到边界框,因为你可能还记得,我说我们的边界框模型在小物体上仍然表现不佳。 所以希望你能猜到我要去哪里,这就是对于边界框模型,记住我们如何在不同的网格单元中输出模型的输出。 而那些早期的网格尺寸不是很好的。 我们该如何解决? U-Net吧! 让我们有一个交叉连接的向上路径。 那么我们就打算做一个U-Net,然后将它们输出来。 因为现在那些更精细的网格单元具有该路径的所有信息,该路径,该路径以及用于杠杆的路径。 当然,这是深度学习,这意味着你不能写一篇论文,说我们只是使用U-Net作为边界框。 你必须发明一个新词,所以这被称为特征金字塔网络或FPN。 这在RetinaNet论文中使用,它是在早期专门关于FPN的论文中创建的。 如果内存服务正常,他们会简单地引用U-Net论文,但它们听起来有点让人觉得有些人可能会觉得有些微不足道。 但实际上,FPN是U-Nets。
好的,就是这样。 我想提到的最后一件事现在是回到边框,因为你可能还记得,我说我们的边框模型在小物体上仍然表现不佳。 所以希望你能猜到我要去哪里,这就是对于边框模型,记住我们如何在不同的网格单元中输出模型的输出。 而那些早期的网格尺寸不是很好的。 我们该如何解决? U-Net吧! 让我们有一个交叉连接的向上路径。 那么我们就打算做一个U-Net,然后将它们输出来。 因为现在那些更精细的网格单元具有该路径的所有信息,该路径,该路径以及用于杠杆的路径。 当然,这是深度学习,这意味着你不能写一篇论文,说我们只是使用U-Net作为边框。 你必须发明一个新词,所以这被称为特征金字塔网络或FPN。 这在RetinaNet论文中使用,它是在早期专门关于FPN的论文中创建的。 如果内存服务正常,他们会简单地引用U-Net论文,但它们听起来有点让人觉得有些人可能会觉得有些微不足道。 但实际上,FPN是U-Nets。
我没有向你展示它的实现,但这将是一个有趣的事情,也许对我们中的一些人来说,我知道有些学生一直试图让它在论坛上运作良好。 所以是的,尝试有趣的事情。 因此,我认为在本课程以及我提到的其他内容之后要考虑的一些事情是使用FPN,也可能尝试使用Kerem的DynamicUnet。 它们都是有趣的东西。
......
......@@ -126,11 +126,11 @@ Jeremy喜欢建立模型的方式:
这不是闻所未闻的 - 我们在第1部分的行星卫星数据中做到了这一点。
**2.围绕我们分类的边框。**
**2.围绕我们分类的边框。**
框有一个非常具体的定义,它是一个矩形,矩形的对象完全适合它,但它不比它必须大。
边框有一个非常具体的定义,它是一个矩形,矩形的对象完全适合它,但它不比它必须大。
我们的工作是获取以这种方式标记的数据和未标记的数据,以生成对象的类和每个对象的边框。 需要注意的一点是,标记此类数据通常更为昂贵 [[37:09](https://youtu.be/Z0ssNAbe81M%3Ft%3D37m09s)] 。 对于对象检测数据集,给注释器一个对象类列表,并要求它们查找图片中任何类型的每一个以及它们的位置。 在这种情况下,为什么没有标记树或跳跃? 这是因为对于这个特定的数据集,它们不是要求注释者找到的类之一,因此不是这个特定问题的一部分。
我们的工作是获取以这种方式标记的数据和未标记的数据,以生成对象的类和每个对象的边框。 需要注意的一点是,标记此类数据通常更为昂贵 [[37:09](https://youtu.be/Z0ssNAbe81M%3Ft%3D37m09s)] 。 对于对象检测数据集,给注释器一个对象类列表,并要求它们查找图片中任何类型的每一个以及它们的位置。 在这种情况下,为什么没有标记树或跳跃? 这是因为对于这个特定的数据集,它们不是要求注释者找到的类之一,因此不是这个特定问题的一部分。
#### 阶段 [[38:33](https://youtu.be/Z0ssNAbe81M%3Ft%3D38m33s)] :
......@@ -186,7 +186,7 @@ Jeremy喜欢建立模型的方式:
#### 加载注释
除了图像之外,还有_注释_ - 显示每个对象所在位置的_边框_ 。 这些是手工贴上的。 原始版本采用XML [[47:59](https://youtu.be/Z0ssNAbe81M%3Ft%3D47m59s)] ,现在有点[难以使用](https://youtu.be/Z0ssNAbe81M%3Ft%3D47m59s) ,因此我们使用了最新的JSON版本,你可以从此[链接](https://storage.googleapis.com/coco-dataset/external/PASCAL_VOC.zip)下载。
除了图像之外,还有_注释_ - 显示每个对象所在位置的_边框_ 。 这些是手工贴上的。 原始版本采用XML [[47:59](https://youtu.be/Z0ssNAbe81M%3Ft%3D47m59s)] ,现在有点[难以使用](https://youtu.be/Z0ssNAbe81M%3Ft%3D47m59s) ,因此我们使用了最新的JSON版本,你可以从此[链接](https://storage.googleapis.com/coco-dataset/external/PASCAL_VOC.zip)下载。
你可以在此处看到`pathlib`如何包含打开文件的功能(以及许多其他功能)。
......@@ -198,7 +198,7 @@ Jeremy喜欢建立模型的方式:
_dict_keys(['images', 'type', 'annotations', 'categories'])_
```
这里`/`不是除以它是路径斜线 [[45:55](https://youtu.be/Z0ssNAbe81M%3Ft%3D45m55s)] 。 `PATH/`让你的孩子走在那条路上。 `PATH/'pascal_train2007.json'`返回一个具有`open`方法的`pathlib`对象。 此JSON文件不包含图像,而是包含边框和对象的类。
这里`/`不是除以它是路径斜线 [[45:55](https://youtu.be/Z0ssNAbe81M%3Ft%3D45m55s)] 。 `PATH/`让你的孩子走在那条路上。 `PATH/'pascal_train2007.json'`返回一个具有`open`方法的`pathlib`对象。 此JSON文件不包含图像,而是包含边框和对象的类。
```
IMAGES,ANNOTATIONS,CATEGORIES = ['images', 'annotations', 'categories']
......@@ -289,7 +289,7 @@ Jeremy喜欢建立模型的方式:
只要你想拥有新密钥的默认字典条目 [[55:05](https://youtu.be/Z0ssNAbe81M%3Ft%3D55m05s)] , [defaultdict就很有用](https://youtu.be/Z0ssNAbe81M%3Ft%3D55m05s) 。 如果你尝试访问不存在的键,它会神奇地使其自身存在,并且它将自身设置为等于你指定的函数的返回值(在本例中为`lambda:[]` )。
在这里,我们创建一个从图像ID到注释列表的dict(边框和类ID的元组)。
在这里,我们创建一个从图像ID到注释列表的dict(边框和类ID的元组)。
我们将VOC的高度/宽度转换为左上/右下,并将x / y坐标切换为与numpy一致。 如果给定的数据集是蹩脚的格式,请花一些时间使事情保持一致,并按照你希望的方式制作它们 [[1:01:24](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h1m24s)]
......@@ -305,7 +305,7 @@ Jeremy喜欢建立模型的方式:
**例1**
* `[ 96, 155, 269, 350]` [96,155,269,350](https://youtu.be/Z0ssNAbe81M%3Ft%3D59m53s)] :一个边界框 [[59:53](https://youtu.be/Z0ssNAbe81M%3Ft%3D59m53s)] 。 如上所述,当我们创建边界框时,我们做了几件事。 首先是我们切换x和y坐标。 其原因在于计算机视觉领域,当你说“我的屏幕是640×480”时,它是高度的宽度。 或者,数学世界,当你说“我的数组是640乘480”时,它是逐列的。 所以枕头图像库倾向于按宽度或逐行逐行进行处理,而numpy则是相反的方式。 第二个是我们要通过描述左上角xy坐标和右下角xy坐标来做事情 - 而不是x,y,高度,宽度。
* `[ 96, 155, 269, 350]` [96,155,269,350](https://youtu.be/Z0ssNAbe81M%3Ft%3D59m53s)] :一个边[[59:53](https://youtu.be/Z0ssNAbe81M%3Ft%3D59m53s)] 。 如上所述,当我们创建边框时,我们做了几件事。 首先是我们切换x和y坐标。 其原因在于计算机视觉领域,当你说“我的屏幕是640×480”时,它是高度的宽度。 或者,数学世界,当你说“我的数组是640乘480”时,它是逐列的。 所以枕头图像库倾向于按宽度或逐行逐行进行处理,而numpy则是相反的方式。 第二个是我们要通过描述左上角xy坐标和右下角xy坐标来做事情 - 而不是x,y,高度,宽度。
* `7` :班级标签/类别
```
......@@ -350,7 +350,7 @@ Jeremy喜欢建立模型的方式:
_('person', 'horse')_
```
有些lib采用VOC格式的边框,所以这让我们在需要时转换回来 [[1:02:23](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h2m23s)] :
有些lib采用VOC格式的边框,所以这让我们在需要时转换回来 [[1:02:23](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h2m23s)] :
```
def bb_hw(a): return np.array([a[1],a[0],a[3]-a[1],a[2]-a[0]])
......@@ -459,7 +459,7 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
不要试图一下子解决所有问题,而是让我们不断进步。 我们知道如何找到每个图像中最大的对象并对其进行分类,所以让我们从那里开始。 Jeremy每天参加Kaggle比赛的时间是半小时 [[1:24:00](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h24m)] 。 在那个半小时结束时,提交一些东西并尝试使它比昨天好一点。
我们需要做的第一件事是遍历图像中的每个边界框并获得最大的边界框。 _lambda函数_只是一种定义内联匿名函数的方法。 在这里,我们用它来描述如何为每个图像排序注释 - 通过限制框大小(降序)。
我们需要做的第一件事是遍历图像中的每个边框并获得最大的边框。 _lambda函数_只是一种定义内联匿名函数的方法。 在这里,我们用它来描述如何为每个图像排序注释 - 通过限制框大小(降序)。
我们从右下角减去左上角并乘以( `np.product` )值得到一个区域`lambda x: np.product(x[0][-2:]-x[0][:2])` 。
......@@ -473,7 +473,7 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
trn_lrg_anno = {a: get_lrg(b) for a,b in trn_anno.items()}
```
现在我们有一个从图像id到单个边框的字典 - 这个图像的最大值。
现在我们有一个从图像id到单个边框的字典 - 这个图像的最大值。
```
b,c = trn_lrg_anno[23] b = bb_hw(b) ax = show_img(open_image(IMG_PATH/trn_fns[23]), figsize=(5,10)) draw_rect(ax, b) draw_text(ax, b[:2], cats[c], sz=16)
......@@ -507,7 +507,7 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
有一点不同的是`crop_type` 。 在fast.ai中创建224 x 224图像的默认策略是首先调整它的大小,使最小边为224.然后在训练期间采用随机平方裁剪。 在验证期间,除非我们使用数据增强,否则我们采用中心作物。
对于边框,我们不希望这样做,因为与图像网不同,我们关心的东西几乎在中间并且非常大,对象检测中的很多东西都很小并且接近边缘。 通过将`crop_type`设置为`CropType.NO` ,它将不会裁剪,因此,为了使其成为正方形,它会使它 [[1:32:09](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h32m9s)] 。 一般来说,如果你裁剪而不是挤压,许多计算机视觉模型的效果会好一点,但是如果你压扁它们仍然可以很好地工作。 在这种情况下,我们绝对不想裁剪,所以这完全没问题。
对于边框,我们不希望这样做,因为与图像网不同,我们关心的东西几乎在中间并且非常大,对象检测中的很多东西都很小并且接近边缘。 通过将`crop_type`设置为`CropType.NO` ,它将不会裁剪,因此,为了使其成为正方形,它会使它 [[1:32:09](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h32m9s)] 。 一般来说,如果你裁剪而不是挤压,许多计算机视觉模型的效果会好一点,但是如果你压扁它们仍然可以很好地工作。 在这种情况下,我们绝对不想裁剪,所以这完全没问题。
```
x,y=next(iter(md.val_dl)) show_img(md.val_ds.denorm(to_np(x))[0]);
......@@ -626,11 +626,11 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
![](../img/1_aztHN3af_MxEhHS71_SUDQ.png)
#### 创建边框 [[1:52:51](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h52m51s)]
#### 创建边框 [[1:52:51](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h52m51s)]
在最大的对象周围创建一个边框可能看起来像你之前没有做过的事情,但实际上它完全是你以前做过的事情。 我们可以创建回归而不是分类神经网络。 分类神经网络是具有sigmoid或softmax输出的网络,我们使用交叉熵,二进制交叉熵或负对数似然丢失函数。 这基本上是什么使它成为分类器。 如果我们最后没有softmax或sigmoid并且我们使用均方误差作为损失函数,它现在是一个回归模型,它预测连续数而不是类别。 我们也知道我们可以像行星竞赛那样有多个输出(多重分类)。 如果我们结合这两个想法并进行多列回归怎么办?
在最大的对象周围创建一个边框可能看起来像你之前没有做过的事情,但实际上它完全是你以前做过的事情。 我们可以创建回归而不是分类神经网络。 分类神经网络是具有sigmoid或softmax输出的网络,我们使用交叉熵,二进制交叉熵或负对数似然丢失函数。 这基本上是什么使它成为分类器。 如果我们最后没有softmax或sigmoid并且我们使用均方误差作为损失函数,它现在是一个回归模型,它预测连续数而不是类别。 我们也知道我们可以像行星竞赛那样有多个输出(多重分类)。 如果我们结合这两个想法并进行多列回归怎么办?
这就是你在考虑差异化编程的地方。 它不像“我如何创建边框模型?”但它更像是:
这就是你在考虑差异化编程的地方。 它不像“我如何创建边框模型?”但它更像是:
* 我们需要四个数字,因此,我们需要一个具有4个激活的神经网络
* 对于损失函数,什么是函数,当它较低时意味着四个数字更好? 均方损失函数!
......@@ -639,7 +639,7 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
#### 仅限Bbox [[1:55:27](https://youtu.be/Z0ssNAbe81M%3Ft%3D1h55m27s)]
现在我们将尝试找到最大对象的边框。 这只是一个带有4个输出的回归。 因此,我们可以使用具有多个“标签”的CSV。 如果你记得第1部分要进行多标签分类,则多个标签必须以空格分隔,并且文件名以逗号分隔。
现在我们将尝试找到最大对象的边框。 这只是一个带有4个输出的回归。 因此,我们可以使用具有多个“标签”的CSV。 如果你记得第1部分要进行多标签分类,则多个标签必须以空格分隔,并且文件名以逗号分隔。
```
BB_CSV = PATH/'tmp/bb.csv' bb = np.array([trn_lrg_anno[o][0] for o in trn_ids]) bbs = [' '.join(str(p) for p in o) for o in bb]
......@@ -673,7 +673,7 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
tfms = tfms_from_model(f_model, sz, crop_type=CropType.NO, **tfm_y=TfmType.COORD** ) md = ImageClassifierData.from_csv(PATH, JPEGS, BB_CSV, tfms=tfms, **continuous=True** )
```
下周我们将看看`TfmType.COORD` ,但是现在,我们才意识到当我们进行缩放和数据增强时,需要在边框中进行,而不仅仅是图像。
下周我们将看看`TfmType.COORD` ,但是现在,我们才意识到当我们进行缩放和数据增强时,需要在边框中进行,而不仅仅是图像。
```
x,y=next(iter(md.val_dl))
......@@ -697,7 +697,7 @@ Matplotlib之所以如此命名是因为它最初是Matlab绘图库的克隆。
fastai允许你使用`custom_head`在`custom_head`上添加自己的模块,而不是默认添加的自适应池和完全连接的网络。 在这种情况下,我们不想进行任何池化,因为我们需要知道每个网格单元的激活。
最后一层有4次激活,每个边框坐标一次。 我们的目标是连续的,而不是分类的,因此使用的MSE损失函数不对模块输出执行任何sigmoid或softmax。
最后一层有4次激活,每个边框坐标一次。 我们的目标是连续的,而不是分类的,因此使用的MSE损失函数不对模块输出执行任何sigmoid或softmax。
```
head_reg4 = nn.Sequential(Flatten(), nn.Linear(25088,4)) learn = ConvLearner.pretrained(f_model, md, **custom_head** =head_reg4) learn.opt_fn = optim.Adam learn.crit = nn.L1Loss()
......@@ -764,7 +764,7 @@ fastai允许你使用`custom_head`在`custom_head`上添加自己的模块,而
![](../img/1_xM98QR8U9kz3MJZDHfz7BA.png)
我们将在下周对此进行更多修改。 在本课之前,如果你被问到“你知道如何创建一个边框模型吗?”,你可能会说“不,没有人教过我”。 但问题实际上是:
我们将在下周对此进行更多修改。 在本课之前,如果你被问到“你知道如何创建一个边框模型吗?”,你可能会说“不,没有人教过我”。 但问题实际上是:
* 你能创建一个有4个连续输出的模型吗? 是。
* 如果这4个输出接近4个其他数字,你能创建一个更低的损失函数吗? 是
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册