草庐IT

YOLOv5源码逐行超详细注释与解读(5)——配置文件yolov5s.yaml

路人贾\'ω\' 2023-06-10 原文

前言

在YOLOv5中网络结构采用yaml作为配置文件,之前我们也介绍过,YOLOv5配置了4种不同大小的网络模型,分别是YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x,这几个模型的结构基本一样,不同的是depth_multiple模型深度和width_multiple模型宽度这两个参数。 就和我们买衣服的尺码大小排序一样,YOLOv5s网络是YOLOv5系列中深度最小,特征图的宽度最小的网络。其他的三种都是在此基础上不断加深,不断加宽。所以,这篇文章我们就以yolov5s.yaml为例来介绍。

yaml这个文件在models文件夹下,我们了解这个文件还是很重要的,如果未来我们想改进算法的网络结构,需要通过yaml这种形式定义模型结构,也就是说需要先修改该文件中的相关参数,然后再修改common.py与yolo.py中的相关代码。(这两个文件下一篇会具体介绍噢~)

文章代码逐行手打注释,每个模块都有对应讲解,一文帮你梳理整个代码逻辑!

友情提示:可以先点再慢慢看哦~

源码下载地址:mirrors / ultralytics / yolov5 · GitCode

     🍀本人YOLOv5源码详解系列: 

YOLOv5源码逐行超详细注释与解读(1)——项目目录结构解析

​​​​​​YOLOv5源码逐行超详细注释与解读(2)——推理部分detect.py

YOLOv5源码逐行超详细注释与解读(3)——训练部分train.py

YOLOv5源码逐行超详细注释与解读(4)——验证部分val(test).py

YOLOv5源码逐行超详细注释与解读(6)——网络结构(1)yolo.py

YOLOv5源码逐行超详细注释与解读(7)——网络结构(2)common.py


目录 

前言

目录 

🚀一、什么是YAML

🚀二、参数配置

🚀三、先验框配置

🚀四、backbone部分

🚀五、Head部分

🚀六、整体模型 ​编辑

🚀七、YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x对比

🚀一、什么是YAML

YAML,即“ YAML Ain’t a Markup Language(YAML 不是一种标记语言)”的递归缩写。YAML真实意思是 “Yet Another Markup Language(仍是一种标记语言)”。是专门用来写配置文件的语言,能很好的与当下的编程语言的一些任务相互协作,非常简洁和强大。

官网上的解释是:

“YAML is a human-friendly data serialization language for all programming languages.”

翻译:YAML 是一种适用于所有编程语言的人性化数据序列化语言。

提到数据序列化语言,我们之前可能比较熟悉的是JSON 和 XML ,YAML与它们类似,但它主要强调这种语言是以数据为中心,而不是以标记为中心,像 XML 语言就使用了大量的标记。并且远比这俩方便和更具可读性。

YAML的使用:

YAML的使用包括了两部分:一个是YAML数据的定义,一个是它在其他程序里如何被使用。

YAML 的基础语法:

  • 大小写敏感
  • 使用缩进表示层级关系
  • 不允许使用tab,只允许空格
  • 缩进的空格数量不重要,只要层级相同的元素左对齐即可
  • ‘#’ 表示注释

🚀二、参数配置

# 1、参数配置
# Parameters
nc: 80  # 所判断目标类别的种类,此处80类
depth_multiple: 0.33  # 模型层数因子 控制模型的深度(BottleneckCSP个数)
width_multiple: 0.50  # 模型通道数因子 控制Conv通道channel个数(卷积核数量)

这段代码有三个参数:

  • nc:  数据集类别个数
  • depth_multiple:  用于控制层的重复的次数(深度)。通过深度参数 depth gain 在搭建每一层的时候,子模块数量=int(number*depth),这样就可以起到一个动态调整模型深度的作用。
  • width_multiple:  用于控制输出特征图的通道数(宽度)。在模型中间层的每一层的卷积核的数量=int(number*width),这样也可以起到一个动态调整模型宽度的作用。

这三个参数,我们会在下一篇模型搭建 yolo.py 文件介绍中见到,先混个眼熟吧:


🚀三、先验框配置

# 2、先验框配置
# anchors
anchors: # 9个anchor,其中P表示特征图的层级,P3/8该层特征图缩放为1/8,是第3层特征
  - [10,13, 16,30, 33,23]  # P3/8 FPN接主干网络下采样8倍后的anchor大小,检测小目标,10,13是一组尺寸,总共三组检测小目标
  - [30,61, 62,45, 59,119]  # P4/16 FPN接主干网络下采样4倍后的anchor大小,检测中目标,共三组
  - [116,90, 156,198, 373,326]  # P5/32 FPN接主干网络下采样2倍后的anchor大小,检测大目标,共三组

YOLOv5使用k-means聚类法来初始化了9个anchors,任意地选择了9个聚类和3个尺度,然后在各个尺度上均匀地划分聚类。在COCO数据集上,这9个聚类是(10 × 13),(16 × 30),(33 × 23),(30 × 61),(62 × 45),(59 × 119),(116 × 90),(156 × 198),(373 × 326)

这9个anchor分别在三个Detect层的feature map中使用,每个feature map的每个grid_cell 都有三个anchor进行预测。

  • 尺度越大的freature map分辨率越大,相对于原图的下采样越小,其感受野也就越小,那么设置的anchors自然越小,如[10,13, 16,30, 33,23],因此对原始图像中的小物体预测较好;
  • 尺度越小的freature map分辨率越小,相对于原图的下采样越大,其感受野越大,设置的anchors自然也就越大,如[116, 90, 156,198, 373,326],因此对原始图像中的大物体预测较好。

如下图所示:


🚀四、backbone部分

# 3、backbone部分
# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2   [3, 32, 6, 2, 2]
   [-1, 1, Conv, [128, 3, 2]],    # 1-P2/4   [32, 64, 3, 2]
   [-1, 3, C3, [128]],            # 2        [64, 64, 1]
   [-1, 1, Conv, [256, 3, 2]],    # 3-P3/8   [64, 128, 3, 2]
   [-1, 6, C3, [256]],            # 4        [128, 128, 2]
   [-1, 1, Conv, [512, 3, 2]],    # 5-P4/16  [128, 256, 3, 2]
   [-1, 9, C3, [512]],            # 6        [256, 256, 3]
   [-1, 1, Conv, [1024, 3, 2]],   # 7-P5/32  [256, 512, 3, 2]
   [-1, 3, C3, [1024]],           # 8        [512, 512, 1]
   [-1, 1, SPPF, [1024, 5]],      # 9        [512, 512, 5]
  ]

这段代码是YOLOv5s的backbone部分, 首先介绍四个参数:

[from, number, module, args]

  • from :   表示当前模块的输入来自那一层的输出,-1表示将上一层的输出当做自己的输入(第0层的-1表示输入的图像)。
  • number:  表示当前模块的重复次数,实际的重复次数还要由上面的参数depth_multiple共同决定,决定网络模型的深度。
  • module:  表示该层模块的名称,这些模块写在common.py中,进行模块化的搭建网络。
  • args:  表示类的初始化参数,用于解析作为 moudle 的传入参数,会在网络搭建过程中根据不同层进行改变,我们后面具体分析。

另外,注释中的#0-P1/2表示该层为第0层,输出后会变成原图的1/2


我们来解释一下每个层参数含义以及图片变化:

原始输入图片: 640*640*3

第0层:Conv层  [-1, 1, Conv, [64, 6, 2, 2]]

  • -1:  输入是图片
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [64, 6, 2, 2]: Conv层的四个参数
    • 64:channel=64
    • 6:kernel_size=6
    • 2:padding=2
    • 2:stride=2
  • 输出图片:320*320*64

 第1层:Conv层  [-1, 1, Conv, [128, 3, 2]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [128, 3, 2]: Conv层的三个参数
    • 128:channel=128
    • 3:kernel_size=3
    • 2:stride=2
  • 输出图片:160*160*128

  第2层:C3层  [-1, 3, C3, [128]]

  • -1:  输入是上一层的输出
  • 3:网络模块数量为3
  • C3: 该层的网络层名字是C3
  • [128]: C3层的参数
    • 128:channel=128
  • 输出图片:160*160*128

 第3层:Conv层  [-1, 1, Conv,  [256, 3, 2]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [256, 3, 2]: Conv层的三个参数
    • 256:channel=256
    • 3:kernel_size=3
    • 2:stride=2
  • 图片变化:80*80*256

  第4层:C3层  [-1, 6, C3,  [256]]

  • -1:  输入是上一层的输出
  • 6:网络模块数量为6
  • C3: 该层的网络层名字是C3
  • [256]: C3层的参数
    • 256:channel=256
  • 图片变化:80*80*256

 第5层:Conv层  [-1, 1, Conv, [512, 3, 2]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [512, 3, 2]: Conv层的三个参数
    • 512:channel=512
    • 3:kernel_size=3
    • 2:stride=2
  • 输出图片:40*40*512

  第6层:C3层  [-1, 9, C3,  [512]]

  • -1:  输入是上一层的输出
  • 9:网络模块数量为9
  • C3: 该层的网络层名字是C3
  • [512]: C3层的参数
    • 512:channel=512
  • 输出图片:40*40*512

 第7层:Conv层  [-1, 1, Conv, [1024, 3, 2]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [1024, 3, 2]: Conv层的三个参数
    • 1024:channel=1024
    • 3:kernel_size=3
    • 2:stride=2
  • 输出图片:20*20*1024

 第8层:C3层  [-1, 3, C3, [1024]]

  • -1:  输入是上一层的输出
  • 3:网络模块数量为3
  • C3: 该层的网络层名字是C3
  • [1024]: C3层的参数
    • 1024:channel=1024
  • 输出图片:20*20*1024

 第9层:SPPF层  [-1, 1, SPPF, [1024, 5]]

  • 主要是对不同尺度特征图的融合
  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • SPPF: 该层的网络层名字是SPPF
  • [1024, 5]: SPPF层的两个参数
    • 1024:channel=1024
    • 5:kernel_size=5
  • 输出图片:20*20*1024

到第9层为止,backbone部分就结束了这个部分会形成三个接口:

  • 第4层的输出:80*80*256
  • 第6层的输出:40*40*512
  • 第9层的输出:20*20*1024

结构示意图如下: 

(图片来源:【YOLO系列】YOLOv5、YOLOX、YOOv6、YOLOv7网络模型结构_DearAlbert的博客) 


 🚀五、Head部分

# 4、head部分
# YOLOv5 v6.0 head
head:
  # 前两个阶段是向上concat
  [[-1, 1, Conv, [512, 1, 1]],    # 10                 [512, 256, 1, 1]
   # nn.upsample不改变channel但是会把图片宽和高都变为2倍
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], # 11    [None, 2, 'nearest']
   # 与上面backbone中的 P4阶段的最后一个输出做一个concat
   # 进行concat的两层必须大小相同、通道数相同 concat之后通道翻倍
   [[-1, 6], 1, Concat, [1]],  # 12 cat backbone P4    [1]
   [-1, 3, C3, [512, False]],  # 13                    [512, 256, 1, False]

   [-1, 1, Conv, [256, 1, 1]], # 14                    [256, 128, 1, 1]
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],   #15   [None, 2, 'nearest']
   [[-1, 4], 1, Concat, [1]],  # 16 cat backbone P3    [1]
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)       [256, 128, 1, False]

   # 后两个阶段是向下concat
   [-1, 1, Conv, [256, 3, 2]],  # 18                   [128, 128, 3, 2]
   [[-1, 14], 1, Concat, [1]],  # 19 cat head P4       [1]
   [-1, 3, C3, [512, False]],   # 20 (P4/16-medium)    [256, 256, 1, False]

   [-1, 1, Conv, [512, 3, 2]],  # 21                   [256, 256, 3, 2]
   [[-1, 10], 1, Concat, [1]],  # 22 cat head P5       [1]
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)     [512, 512, 1, False]
   # 有三个检测层,分别是在17层下面、20层下面、23层下面
   [[17, 20, 23], 1, Detect, [nc, anchors]],  # 24     [80,[[10,13,16,30,33,23],[30,61.[128.256.512]1
  ]

YOLOv5中的Head包括NeckDetect两部分。

Neck采用了FPN+PAN结构,Detect结构和YOLOv3中的Head一样。其中BottleNeckCSP带有False,说明没有使用残差结构,而是采用的backbone中的Conv。


四个参数和上面backbone一样就不再解释了,我们来继续解释一下每个层参数含义以及图片变化:

上一个阶段输出大小:20*20*1024

首先前两个阶段是向上concat

第10层:Conv层  [-1, 1, Conv, [512, 1, 1]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [512, 1, 1]: Conv层的三个参数
    • 512:channel=512
    • 1:kernel_size=1
    • 1:stride=1
  • 输出图片:20*20*512

 第11层:Upsample层  [-1, 1, nn.Upsample, [None, 2, 'nearest']]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • nn.Upsample: 该层的网络层名字是Upsample
  • [None, 2, 'nearest'] Upsample层的三个参数
    • Nonesize=None(指定输出的尺寸大小)
    • 2scale_factor=2(指定输出的尺寸是输入尺寸的倍数)
    • 'nearest'mode='nearest'(默认: ‘nearest’
  • 输出图片:通过该层之后特征图不改变通道数特征图的长和宽会增加一倍——40*40*512

  第12层:Concat层  [[-1, 6], 1, Concat, [1]]

  • [-1, 6]:  输入是上一层和第6层的输出
  • 1:网络模块数量为1
  • Concat: 该层的网络层名字是Concat
  • [1]: Concat层的参数
    • [1]:拼接的维度=1
  • 输出图片:通过该层之后特征图与第6层(p4阶段)的输出进行特征图的融合——40*40*1024(即输出40×40×512contact40×40×512=40×40×1024)

 第13层:C3层  [-1, 3, C3, [512, False]]

  • -1:  输入是上一层的输出
  • 3:网络模块数量为1
  • C3: 该层的网络层名字是C3
  • [512, False] C3层的两个参数
    • 512:channel=512
    • False没有残差模块
  • 输出图片:40*40*512

  第14层:Conv层  [-1, 1, Conv, [256, 1, 1]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [256, 1, 1]: Conv层的三个参数
    • 256:channel=256
    • 1:kernel_size=1
    • 1:stride=1
  • 输出图片:40*40*256

 第15层:Upsample层  [-1, 1, nn.Upsample, [None, 2, 'nearest']]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • nn.Upsample: 该层的网络层名字是Upsample
  • [None, 2, 'nearest'] Upsample层的三个参数
    • Nonesize=None(指定输出的尺寸大小)
    • 2scale_factor=2(指定输出的尺寸是输入尺寸的倍数)
    • 'nearest'mode='nearest'(默认: ‘nearest’
  • 输出图片:通过该层之后特征图不改变通道数特征图的长和宽会增加一倍——80*80*256

  第16层:Concat层  [[-1, 4], 1, Concat, [1]]

  • [-1, 4]:  输入是上一层和第4层的输出
  • 1:网络模块数量为1
  • Concat: 该层的网络层名字是Concat
  • [1]: Concat层的参数
    • [1]:拼接的维度=1
  • 输出图片:通过该层之后特征图与第4层(p3阶段)的输出进行特征图的融合——80*80*512(即输出80×80×256contact80×80×256=80×80×512)

 第17层:C3层  [-1, 3, C3, [256, False]]

  • -1:  输入是上一层的输出
  • 3:网络模块数量为1
  • C3: 该层的网络层名字是Conv
  • [256, False] C3层的两个参数
    • 256:channel=256
    • False没有残差模块
  • 输出图片:80*80*256

后两个阶段是向下concat

第18层:Conv层  [-1, 1, Conv, [256, 3, 2]]

  • -1:  输入是上一层的输出
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [256, 1, 1]: Conv层的三个参数
    • 256:channel=256
    • 3:kernel_size=3
    • 2:stride=2
  • 输出图片:40*40*256

  第19层:Concat层  [[-1, 14], 1, Concat, [1]]

  • [-1, 14]:  输入是上一层和第14层的输出
  • 1:网络模块数量为1
  • Concat: 该层的网络层名字是Concat
  • [1]: Concat层的参数
    • [1]:拼接的维度=1
  • 输出图片:通过该层之后特征图与第14层的输出进行特征图的融合——40*40*512(即输出40×40×256contact40×40×256=40×40×512)

 第20层:C3层  [-1, 3, C3, [512, False]]

  • -1:  输入是上一层的输出
  • 3:网络模块数量为3
  • C3: 该层的网络层名字是C3
  • [512, False] C3层的两个参数
    • 512:channel=512
    • False没有残差模块
  • 输出图片:40*40*512

第21层:Conv层  [-1, 1, Conv, [512, 3, 2]]

  • -1:  输入是图片
  • 1:网络模块数量为1
  • Conv: 该层的网络层名字是Conv
  • [512, 3, 2]: Conv层的三个参数
    • 512:channel=512
    • 3:kernel_size=3
    • 2:stride=2
  • 输出图片:20*20*512

  第22层:Concat层  [[-1, 10], 1, Concat, [1]]

  • [-1, 10]:  输入是上一层和第10层的输出
  • 1:网络模块数量为1
  • Concat: 该层的网络层名字是Concat
  • [1]: Concat层的参数
    • [1]:拼接的维度=1
  • 输出图片:通过该层之后特征图与第10层的输出进行特征图的融合——20*20*1024(即输出20×20×512contact20×20×512=20×20×1024)

 第23层:C3层  [-1, 3, C3, [1024, False]]

  • -1:  输入是上一层的输出
  • 3:网络模块数量为3
  • C3: 该层的网络层名字是C3
  • [1024, False] C3层的两个参数
    • 1024:channel=1024
    • False没有残差模块
  • 输出图片:20*20*1024

 第24层:Detect层  [[17, 20, 23], 1, Detect, [nc, anchors]]

  • [17, 20, 23]:  表示把第17、20和23三层作为Detect模块的输入
  • 1:网络模块数量为1
  • Detect: 该层的网络层名字是Detect
  • [nc, anchors]: 初始化Detect模块的参数
    • nc:类别个数
    • anchors超参数 anchors的值
  • 输出图片:20*20*1024

结构示意图如下: 


🚀六、整体模型 


🚀七、YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x对比

精确度对比

配置对比 

           

YOLOv5sYOLOv5mYOLOv5lYOLOv5x
depth_multiple 0.33         0.67 1.0 1.33
width_multiple        0.50     0.75  1.01.25

BottleneckCSP数

BCSPn(True)

1,3,32,6,6 3,9,9 4,12,12
BottleneckCSP数BCSPn(False)1234
Conv卷积核数量

32,64,128,

256,512

48,96,192,

384,768

64,128,256,

512,1024

80,160,320,

640,1280

深度对比 

 宽度对比 


本文到这里就结束了,有很多参数具体如何使用可以参见下一篇yolo.py的介绍(点这里直达!

另外,想更加深入学习yaml文件的话,推荐看这篇→CSDN独家首发!万字长文,YOLOv5/v7/v8算法模型yaml文件史上最详细解析与教程!小白也能看懂!掌握了这个就掌握了魔改YOLO的核心!_迪菲赫尔曼的博客-CSDN博客

有关YOLOv5源码逐行超详细注释与解读(5)——配置文件yolov5s.yaml的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  8. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

  9. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  10. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

随机推荐