Darknet中函数分析
随机打乱数据
代码在data.c源文件中
void randomize_data(data d) { int i; for(i = d.X.rows-1; i > 0; --i){ // 从最后一个元素位置开始,当前位置为i int index = rand()%i;// 从i(不包括)之前的所有位置随机选择一个位置index float *swap = d.X.vals[index]; // 交换index和i处的指针 d.X.vals[index] = d.X.vals[i]; d.X.vals[i] = swap;
swap <span class="token operator">=</span> d<span class="token punctuation">.</span>y<span class="token punctuation">.</span>vals<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">;</span> d<span class="token punctuation">.</span>y<span class="token punctuation">.</span>vals<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> d<span class="token punctuation">.</span>y<span class="token punctuation">.</span>vals<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> d<span class="token punctuation">.</span>y<span class="token punctuation">.</span>vals<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> swap<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
可以看到整个打乱过程只有指针指向在不断发生变化,数据在内存中的位置不变。
im2col实现
代码在im2col.c源文件中
float im2col_get_pixel(float *im, int height, int width, int channels, int row, int col, int channel, int pad) { row -= pad; col -= pad;
<span class="token keyword">if</span> <span class="token punctuation">(</span>row <span class="token operator"><</span> <span class="token number">0</span> <span class="token operator">||</span> col <span class="token operator"><</span> <span class="token number">0</span> <span class="token operator">||</span> row <span class="token operator">>=</span> height <span class="token operator">||</span> col <span class="token operator">>=</span> width<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">return</span> im<span class="token punctuation">[</span>col <span class="token operator">+</span> width<span class="token operator">*</span><span class="token punctuation">(</span>row <span class="token operator">+</span> height<span class="token operator">*</span>channel<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
}
//From Berkeley Vision’s Caffe!
//https://github.com/BVLC/caffe/blob/master/LICENSE
void im2col_cpu(float data_im, // 输入的图像数据,内存中按行排列成一维
int channels, // 通道数
int height, int width, // 图像的高和宽
int ksize, // 卷积核的高和宽,这里默认卷积核高和宽大小一样
int stride, // 卷积时的步长,这里默认高和宽两个方向上步长一样
int pad, // 图像的填充,这里默认高和宽上填充一样
float data_col // 最终输出的数据
) {
int c,h,w;
int height_col = (height + 2pad - ksize) / stride + 1; // 卷积后的图像尺寸,可以想象,其中每个点对应图像的一个卷积区域,卷积区域大小是channels * ksize * ksize,即下面的channels_col。
int width_col = (width + 2pad - ksize) / stride + 1;
<span class="token keyword">int</span> channels_col <span class="token operator">=</span> channels <span class="token operator">*</span> ksize <span class="token operator">*</span> ksize<span class="token punctuation">;</span> <span class="token comment">// 图像上每个卷积区域展成一列后的大小,比如 // ksize=3,图像通道数为3,那么channels_col为27</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>c <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> c <span class="token operator"><</span> channels_col<span class="token punctuation">;</span> <span class="token operator">++</span>c<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> w_offset <span class="token operator">=</span> c <span class="token operator">%</span> ksize<span class="token punctuation">;</span> <span class="token comment">// 0, 1, 2, 0, 1, 2, 0, 1, 2, ... 宽的相对偏移</span>
<span class="token keyword">int</span> h_offset <span class="token operator">=</span> <span class="token punctuation">(</span>c <span class="token operator">/</span> ksize<span class="token punctuation">)</span> <span class="token operator">%</span> ksize<span class="token punctuation">;</span> <span class="token comment">// 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, ...高的相对偏移</span>
<span class="token keyword">int</span> c_im <span class="token operator">=</span> c <span class="token operator">/</span> ksize <span class="token operator">/</span> ksize<span class="token punctuation">;</span> <span class="token comment">// 9个0, 9个1, 9个2 通道序号,(c_im, h_offset, w_offset)是卷积区域的相对坐标</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>h <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> h <span class="token operator"><</span> height_col<span class="token punctuation">;</span> <span class="token operator">++</span>h<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 有height_col * width_col个卷积区域,遍历每一个卷积区域,对于每个区域,计算它的c位置处的图像像素值</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>w <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> w <span class="token operator"><</span> width_col<span class="token punctuation">;</span> <span class="token operator">++</span>w<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> im_row <span class="token operator">=</span> h_offset <span class="token operator">+</span> h <span class="token operator">*</span> stride<span class="token punctuation">;</span> <span class="token comment">// 相对于图像的行坐标</span>
<span class="token keyword">int</span> im_col <span class="token operator">=</span> w_offset <span class="token operator">+</span> w <span class="token operator">*</span> stride<span class="token punctuation">;</span> <span class="token comment">// 相对于图像的列坐标</span>
<span class="token keyword">int</span> col_index <span class="token operator">=</span> <span class="token punctuation">(</span>c <span class="token operator">*</span> height_col <span class="token operator">+</span> h<span class="token punctuation">)</span> <span class="token operator">*</span> width_col <span class="token operator">+</span> w<span class="token punctuation">;</span> <span class="token comment">// </span>
data_col<span class="token punctuation">[</span>col_index<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">im2col_get_pixel</span><span class="token punctuation">(</span>data_im<span class="token punctuation">,</span> height<span class="token punctuation">,</span> width<span class="token punctuation">,</span> channels<span class="token punctuation">,</span>
im_row<span class="token punctuation">,</span> im_col<span class="token punctuation">,</span> c_im<span class="token punctuation">,</span> pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
这是caffe中卷积操作之前的关键步骤,对三维图像进行变形,将传统卷积操作变成矩阵形式的卷积操作。
简便起见,设channels = 1,即图像是个单通道图。data_im为
05101520161116212712172238131823491419240123456789101112131415161718192021222324
0
a
m
p
;
1
a
m
p
;
2
a
m
p
;
3
a
m
p
;
4
5
a
m
p
;
6
a
m
p
;
7
a
m
p
;
8
a
m
p
;
9
10
a
m
p
;
11
a
m
p
;
12
a
m
p
;
13
a
m
p
;
14
15
a
m
p
;
16
a
m
p
;
17
a
m
p
;
18
a
m
p
;
19
20
a
m
p
;
21
a
m
p
;
22
a
m
p
;
23
a
m
p
;
24
05101520161116212712172238131823491419240123456789101112131415161718192021222324 \begin{matrix}0 & 1 & 2 & 3 & 4 \\5 & 6 & 7 & 8 & 9 \\10 & 11 & 12 & 13 & 14 \\15 & 16 & 17 & 18 & 19 \\20 & 21 & 22 & 23 & 24 \\\end{matrix}
0510152016111621271217223813182349141924012345678910111213141516171819202122232405101520amp;1amp;6amp;11amp;16amp;21amp;2amp;7amp;12amp;17amp;22amp;3amp;8amp;13amp;18amp;23amp;4amp;9amp;14amp;19amp;243×3×3=27列。此时,再将kernel拉伸成一列,卷积过程变成了矩阵乘法:
⎡
⎣
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢
0125671011121236781112132347891213145671011121516176781112131617187891213141718191011121516172021221112131617182122231213141718
⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢0125671011121236781112132347891213145671011121516176781112131617187891213141718191011121516172021221112131617182122231213141718
⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢0125671011121236781112132347891213145671011121516176781112131617187891213141718191011121516172021221112131617182122231213141718