Python+Caffe学习记录

learn_numpy_python

  1. dot = np.dot(x1,x2) 矩阵点积,一维是向量内积,多维是矩阵乘法运算,矩阵相乘一般采用dot,而元素对应相乘一般使用*

  2. 1
    2
    3
    4
    5
    outer = np.outer(a,b)   #矩阵点乘 a = [a0, a1, ..., aM],b = [b0, b1, ..., bN]
    [[a0*b0 a0*b1 ... a0*bN ]
    [a1*b0 .
    [ ... .
    [aM*b0 aM*bN ]]
  3. mul = np.multiply(x1,x2) #对应元素相乘。

    1. 图像的表示方法是1797 × 64
      picture_data = data.reshape(-1,8,8,1) -1表示不知道,两个8表示8行8列,1表示一维空间(彩色是在处理的时候是三维空间RGB),整短代码就是说,把 1797*64这个矩阵,变换成8*8的不知道多少个的矩阵,

      1. arr.reshape(3,3)arr变成一个3×3的矩阵,行、列

T20190418:

  1. 1
    2
    3
    np.array[:]->全部元素。
    np.array[1:]->从第一个到最后一个。
    [[1,2,3],[1,2,3]] -> np.array[1:][0] = 1;
  2. 1
    X_flatten = X.reshape(X.shape[0], -1).T      # X.T is the transpose of X.where each column represents a flattened image
  3. train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T

    train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[1]*train_set_x_orig.shape[2]*train_set_x_orig.shape[3],-1)
    的区别:

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

reshape -> 以行为先,计算得到每行多少个数据,然后铺满。
故当 input data image = 64 x 64 x 3 x 209 时
reshape(209,-1).T -> 每一行存 64 x 64 x 3 个相邻元素。
reshape(64 x 64 x 3,-1) -> 每一行存 209 个相邻元素,这个209个是一张img中的像素
[
[
[
[12,33,22 -> channel[0]] -> cols[0]
[..,..,..]
..
[] -> col[63]
] -> rows[0]
[
[,,]
]
[]
...
[] ->row[63]
] -> image[0]

[..
..] -> image[Indx]
[..
..]
]//209
  1. 循环语句、条件
    1
    2
    3
    4
    if ... :
    ( ~ -> 非)
    else:
    for i in range(m):
1
2
3
4
5
python 中 map 的构建:
m{};
m{"key1" : value1,
"key2" : value2
}

T20190425:

1
2
3
4
PYTHON 中的" %S"%用法:
name= input("Please input your name: ")
print("Hello, %s good morning!" %name)
"%s1"%S2 s1放置的是一个字符串(格式化字符串) S2放置的是一个希望要格式化的值
1
array: [1] * 2+[12,2]=[1,1,12,2]

T20190426: 安装PyCharm, 配置Pycaffe

Python 解释器为C:\Development\Anaconda3\envs\py36\python3.6
Anaconda3 已经安装好了numpy matplot scipy 等库
Pycaffe 接口的配置步骤:
参考happynearreadme :[blog][https://github.com/happynear/caffe-windows/blob/ms/README.md]

  1. 必须是python2.7版本,因为third party libraries 是用python2.7制作的,且_caffe.cpp中的头文件也是python2.7的格式。

  2. Miniconda下载时可以勾选add to path,将其加入环境变量中。然后使用prompt下载python的几个库。

    1
    2
    conda install --yes numpy scipy matplotlib scikit-image pip
    pip install protobuf
  3. 修改caffe项目sln中的CommonSettings.props文件

1
2
3
4
5
6
7
8
1. <PythonSupport>true</PythonSupport>
2.
<PropertyGroup Condition="'$(PythonSupport)'=='true'">
</PropertyGroup>
<PythonDir> C:\Development\Miniconda2 </PythonDir>
<LibraryPath>$(PythonDir)\libs;C:\Development\Miniconda2\libs;$(LibraryPath)</LibraryPath>
<IncludePath>$(PythonDir)\include;C:\Development\Miniconda2\include;$(IncludePath)</IncludePath>
</PropertyGroup> #(必须时绝对路径)可以解决cannot open python2.7, cannot find pyconfig.h等文件无法找到或打开问题
  1. 配置pycaffe Property
1
2
3
4
5
6
1.include Directoies: 设为 
1.C:\Development\Miniconda2\Lib\site-packages\numpy\core\include
2.C:\Development\Miniconda2\include
2.library Directories 设为
1.C:\Development\Miniconda2\libs
3.Treat Warnings as error = no
  1. 编译Pycaffe文件
  2. Set PythonPath environment variable refer to <caffe_root>\Build\x64\Release\pycaffe

T20190427:

  1. 成功使用Python+Pycharm训练起了FCN,数据集为onhand10K的手势数据集。2分类问题。
  2. 参考了Blog(FCN训练不收敛的原因分析和最详细的FCN训练与测试自己的数据程序配置)
    1. Pycaffetrain.prototxt, solve.prototxt , deploy.prototxt.
      1. Pycharm中导入写Caffe层(prototxt层)是没有智能提示的,因为他是用python外包的。直接调用即可。
      2. 参考(caffe Python API整理):(参考博客[blog][https://www.jianshu.com/p/1a420445deea])

DATA层:

返回data和label可以在之后的层中作为输入。

1
2
3
4
5
data, label = L.Data( batch_size=batch_size, 
backend=P.Data.LMDB, //数据库来源
source='mnist/mnist_test_lmdb',
transform_param=dict(scale=1./255),
ntop=2 #指定返回两个top blob )

卷积层:

1
2
3
4
conv1 = L.Convolution( data_blob, 
kernel_size=5,
num_output=20,
weight_filler=dict(type='xavier') )

这些都可以写成内部的函数然后就有智能提示啦啦啦,顺便还可以将一个conv+relu合成一块。

1
2
3
4
def conv(..,..,..)
conv1 = L.Convolution;
relu1 = L.ReLU;
return conv1,relu1

需要注意的是:前一个的输出名字得作为第二个的输入时的名字名称要匹配。

全连接层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
n.fc = L.InnerProduct(n.pool,
param=
[
dict(lr_mult=1,
decay_mult=1),
dict(lr_mult=1,
decay_mult=1)
],
inner_product_param =
dict(
num_output = 4096,
weight_filler = dict(type='xavier'),
bias_filler = dict(type='constant', value=0)
)
)

损失层

1
net.loss = L.SofemaxWithLoss(net.fc7_1, net.label)

一般论文创新点会有自己的定义的层,GitHub上会有该层的代码。FCN是一个python的数据读入层

fine-tune 模型:

[FCN_github][https://github.com/shelhamer/fcn.berkeleyvision.org]
[参考了Blog][https://blog.csdn.net/jiongnima/article/details/78549326]

  1. fine-tune时初始值设为其他模型中的值,只需要将名称设为与下载模型中名称一样即可。
    使用 solver.net.copy_from(weights) weights 是下载模型的路径。

  2. 所以有些不需要初始化的层必须要修改其名字。并且注意层与层的输出维度的修改。(比如FCN是21类,而手只有2类)

  3. 数据格式:
    FCN的数据格式可以在caffe训练时的error猜测。不要忽略batch_size
    label的类别是整数可以为0,1,2,3。共4类。则一张img中只能出现0,1,2,3四个值。不要小数。

  4. txt,数据名称列表。

    1. 获取可使用提供的python模板。get_txt.
    2. 这个txt产生一个train的和一个test的,里面的格式随solve.py里面取出img时的字符串处理有关,在FCN中作者是"{}/.../{}.jpg".format(self.*,index); 所以可以看出来txt中只要前缀不要后缀jpg,且train.prototxtdata的路径不用写完,那只是个总路径,路径中的...可以分为train_image文件夹 ,以及 test_image文件夹. 所以txt文件需要存在train.prototxtdataset的路径中。(图像的上一层路径)。不然会有路径错的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|train.txt
|test.txt
|dataset
|train
|train_image_224x224.
|0.jpg....
|10000.jpg
|train_mask_224x224.
|0.jpg...
|10000.jpg
|test
|test_image_224x224.
|0.jpg....
|1702.jpg
|test_mask_224x224.
|0.jpg...
|1702.jpg
  1. solve.py
    分为两个数据集:一个是VOC一个是SBDD,一个作为训练集,一个作为测试集。

    1
    2
    in_ = in_[:,:,::-1],逆序。
    in_ -= self.mean。减去均值。
  2. 注意
    几个prototxt的位置。数据集的位置,需要仔细。
    详细的代码注释。

T20190428:

终于终于能训练自己的数据集了。FCN训练成功。

  1. 参考”FCN训练不收敛的原因分析和最详细的FCN训练与测试自己的数据程序配置”

  2. 论文GitHub上一般会提供作者自己new的层,与一些py文件,这些文件都和训练有很大的关系。

    1. FCN中提供了许多.py文件:
      1. net.py //用python生成ptototxt,注意:没有智能提示,可以封装写成内部函数来方便调用。其中返回值是层的名字(自定义)。
        1. 注意的是当初始化设为别人的模型来finetune时名字相同的会赋值,所以要修改自己需要训练的层名字。
        2. infer时,net.load()也是使用的这个方法,只不过基本所有的层都是重名的,然后赋值得到训练的模型数据,做一次forward().
        3. inferdeploy去掉了最后的softmaxwithloss,以及两个dropout层。在运行solver.py时可以看到console输出ignore了这些层。
      2. solver.py //调用caffe训练的py.在这里要先load别人的训练好的模型来finetune
        1. 设置gpu型号需要int强转。
        2. 在solver中不要caffe的自我test,而是采用了自定义的测试层。seg_tests()
        3. 需要有个train.txt存放数据的索引(名称)
      3. voc_layers.py //自定义py层,调用用L.Python(模块名字,类型,输出参数个数,字典),返回值是top的两个
        1. 这是数据层,所以没有bckforward
        2. '{}/{}.txt'.format需要改路径。{}是上级目录,包含了train,test,
      4. vis.py //后面可视化数据的工具 没有读懂
      5. score.py //测试时调用
      6. surgery.py //初始化数据
      7. my_solver.py //是使用opencv版本的可视化数据。没有使用论文作者提供的vis.py
    2. 输入时是减去了均值的
    3. 数据长宽大小格式是224x224,label也是224x224,只是通道数量不同
    4. label不是小数而是类。所以可视化mask是黑的,最大灰度值为1.

T20190501:学习style transfer 的源码记录

style transfer 是用PyCaffe实现的

  1. python 中主函数参数的parse:

    1
    2
    3
    4
    5
    6
    1import argparse    首先导入模块
    2)parser = argparse.ArgumentParser() 创建一个解析对象
    3)parser.add_argument() 向该对象中添加你要关注的命令行参数和选项
    1.parser.add_argument("-s", "--style-img", type=str, required=True, help="input style (art) image")
    -> name+类型。第二个双横线之后的名字 是用来获取的。args.style_img,这里——=_.
    4)args = parser.parse_args() 进行解析,在args中得到数据
  2. caffe load_image(image_path) ->go to impletation:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ##源码
    img = skimage.img_as_float(skimage.io.imread(filename, as_grey=not color)).astype(np.float32)
    if img.ndim == 2:
    img = img[:, :, np.newaxis]
    if color:
    img = np.tile(img, (1, 1, 3))
    elif img.shape[2] == 4:
    img = img[:, :, :3]
    return img
    ###
  3. skimage.io.imread\cv2.imread 保存后的都是numpy格式,但cv2的存储格式是BGR,而skimage的存储格式是RGB

  4. 1
    2
    3
    4
    5
    6
    7
    8
    skimage.img_as_float(image).astype(np.float32)
    img_as_float Convert an image to floating point format, with values in [0, 1]. Is similar to img_as_float64, but will not convert lower-precision floating point arrays to float64.
    img_as_float32 Convert an image to single-precision (32-bit) floating point format, with values in [0, 1].
    img_as_float64 Convert an image to double-precision (64-bit) floating point format, with values in [0, 1].
    img_as_uint Convert an image to unsigned integer format, with values in [0, 65535].
    img_as_int Convert an image to signed integer format, with values in [-32768, 32767].
    img_as_ubyte Convert an image to unsigned byte format, with values in [0, 255].
    img_as_bool Convert an image to boolean format, with values either True or False.
  5. astype(np.float32) 将数据转换为数组的数据float32格式。一张彩色图片转换为灰度图后,它的类型就由unit8变成了float-[0-1]之间。

  6. slice

    1
    2
    3
    对于np.array对象,可以使用数组的切片来分割数组。
    1) a=array([1,2,3]) a[:2] ->只取前[0-2)项数据
    2) 对于高维的,可以取高纬度的每一切片,img[:,:,:3],如果Img有4个通道+alpha,则只取其前三(H,W,C)
  7. img.ndim返回数组的维度。rgb是三维。

    1
    2
    3
    img = img[:, :, np.newaxis],如果是2维的则在第三位新建一维
    如果还设为color图,那么将前一层的数据叠2层:
    im =np.tile(img,(1,1,3))
  8. StyleTransfer

    1
    2
    3
    4
    5
    6
    1. for layer in self.net.blobs:
    只返回键值,即conv1_1层的名字。
    2.load_model:
    1.transformer transformer.set_channel_swap("data", (2,1,0))#将 0,2维通道交换。
    2.transformer.set_transpose("data", (2,0,1)) #改变维度的顺序,由原始图片(227,227,3)变为(3,227,227)
    3.set_raw_scale: #大小0-255

T20190429:

  1. python 中函数也是对象,可存入键值对中,也可以键值调用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    e.g:
    def move_up(x)
    x[1] += 1
    def....
    ...
    ...
    actions={
    'up':move_up,
    'down':move_down,
    'left':move_left,
    'right':move_right
    }
    for move in moves:
    actions[move](coord)
  2. lamada 函数:
    1.匿名函数,使用:lamada x:x[1],对输入变量输出x的第一维

  3. python 中高维度的argmax(axis=*)

    1. out = net.blobs['score'].data[0].argmax(axis=0)
      该行可以很方便地寻找到每一个像素点所对应的最大概率类。
      在C个H*W层上遍历每一个点,看该点在哪个通道(预测的类)上的概率取最大值,并且返回的是该通道的下标。
      1
      2
      3
      4
      array.argmax(axis)如果array是一维的话,只返回第一次出现的最大值的索引
      axis : int, 可选,默认情况下,索引的是平铺的数组,否则沿指定的轴。可以按照每一个维度进行排序。但不是整个排序。
      array.argsort() 对所有的数据进行排序,返回的Index,最小的在最前面。如果不加参数,则是默认使用最深的维度(shape的最后一个数所对应),的来排序
      argsort(axis=0) 以第一维排序。看第一维有几层,那么返回的index最大是几。

简单的例子:

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
#!/usr/bin/python
# -*- coding:utf8 -*-
import numpy as np
a = np.array([[[1,0,1,1],[6,4,3,4],[3,5,2,1]],[[4,2,2,0],[5,3,2,1],[3,1,0,7]]])
b= np.array([[1,1,1],[0,1,2]])
print(a)
#print(b)
#argmax(axis=1)
```
以第几维排序,然后返回的是第几维`index`,返回的是某维度的最大值的`index`
```python
#axis ==0 ->一维:将所有数据以第1维单独排列,每一个取最大。
#a=[2x3x4]
print(a.argmax(axis=0)) #返回的是降axis=0维的长度(axis=1 x axis=2)[3x4],而值为axis=0维的个数。此处行维2个[0,1]
print(a.argmax(axis=2)) #返回的是降axis=2维的长度(axis=0 x axis=1)[2x3],而值为axis=2维的个数。此处行维4个[0-3]
print ('eg2:')
a='python'
b=a[::-1] #间距为1,倒序
print (b)
c=a[::-2] #间距为2
print (c)
a = [0,1,2,3,4,5,6,7,8,9]
b = a[1:3] # [1,2]
#a[i,j,x] 取a的i到j[i,j),步长为x #Out[13]: [1, 2]
c=a[1:5] #Out[15]: [1, 2, 3, 4]
d=a[1:5:1] #Out[17]: [1, 2, 3, 4]
e=a[1:5:2] #Out[19]: [1, 3]

  1. map{}:
    map{}Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def f(x):
    return x*x
    print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])//map()函数不改变原有的 list,而是返回一个新的 list。
    ```
    ```python
    l=map(int,'1234')
    for i in l:
    print(type(i))
    print(i)
  2. format() 字符串格式化。

    1
    2
    str = 'a is b and {} is {} not {}'.format('aa','bb',1)
    str = 'a is b and {0} is {2} not {1}'.format('aa','bb',1)//可改变其顺序
1
2
3
4
5
6
7
8
9
1.对齐补齐:
1.str = '5 length {:0>5d}'.format(a=1) #00001 #右补0
2.str = '5 length {:0<5d}'.format(a=1) #10000 #左补0
2.小数精度:
1.print('{:.6f}'.format(a)) #小数点后6位。
2.print('{:.1e}'.format(a)) #小数点后一位+科学指数法。
3.template = '{name} is {age} years old'
c= template.format(name='Tim',age=8)
5.Python rstrip() 删除 string 字符串末尾的指定字符(默认为空格).

T20190501:

python 中的 类:

1
2
3
4
5
6
7
8
class className:
"""description"""
def __init__(self,**args): """构造参数可选择明确指出,也可以不定长。"""
self.param_1 = ..
self.param_2 = ..
"""这是类的构造函数,python中每个类的函数第一个参数必须适合self,这是类的存储空间指针,所以变量都是用self注册"""
"""函数中_一个下划线是protect函数,可被继承,__两个下划线则是私有函数,不能被继承,不带下划线的是public"""
"""__在编译时会在前面加上类名:__ClassName__Param__"""

T20190510:

squeeze()

1
caffe.io.load_image('').squeeze() 读入图像是0-1之间,squeeze()是去掉 维度数量为1 的维度

np.newaxis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
im[np.newaxis,np.newaxis,:,:]是在im的原来基础上新了两个层,然后将源数据放在其::对应上

im[None,None,:,:]
```
为什么列的参数改成`None`,输出的shape都变了,这里大家要知道,None代表新增加一个维度,它有一个别称叫newaxis,大家可以输出一下`numpy.newaxis`就知道了,那么这个别称应该顾名思义了吧。那么为什么是5x1x5,而不是

#### **`参数前面添加*`**
```python
python 中参数前面添加*:
def accept(*s): #((0, 1, 2, 3, 7.5),)
print(s)

list = (0, 1, 2, 3, 7.5)
print(list)
accept(list)

分别打印一下slist,输出是这样的:(0, 1, 2, 3, 7.5) ((0, 1, 2, 3, 7.5),)
可以看出当函数中参数位置上有号时,其的作用时不确定输入参数的大小:传入的变量会被收集为tuple
对于键值map则需要**来解包。

1
2
data[...]它是省略所有的冒号来用省略号代替,当无法显示知道data的维度信息的时候
range(2) -> [0,1] 从0开始。

T20190519:

net

1
2
3
4
5
6
7
8
9
1. net.blobs['data'].reshape(*im_input.shape) 将data层reshape到输入图像的大小,这里时灰度图像。
net.blobs['data'].data[...] = im_input 因为data 已经reshape到指定大小所以其数据只需要直接全部赋值即可。

2. net.blobs['conv'].data.shape 是该层的输出数据,是进过卷积后的数据,所以其数据大小是可以根据公式计算得到的。其通道数和卷积核数相同。、
该层的data层就是该层的输出。

3. net.params['conv'][1].data[0] = 1. #其中net.blobs['层名字']可以得到层的数据。
#而net.params['层名字']可以得到层的权值
net.forward()

np.array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. array[0,1] = array[0][1],array[1,:2], ->第一维的第一到二维的元素。

2. conv_params = {pr: (net_full_conv.params[pr][0].data, net_full_conv.params[pr][1].data) for pr in params_full_conv} 这时在conv_params 中是net_full_conv的引用别名,对conv_params的修改会作用于net_full_conv。

3. np.array.flat只是将array用flat的方式访问,其返回的是一个迭代器。可以使用强制转换:list(np.array.flat)

4. np.array.flatten 是返回的flat后的一个副本List

5. np.array([1,2,3]). ()->tuple []->list {}->dict
都支持 + *运算, shape 返回的是元组(),超过范围可以是空。

6. np.array.mean(axis) -> axis 求和该维度/该维度的数量

7.net.blobs['data'].reshape ->调用的是blob的reshape 函数

forward()

pycaffe 中不同于c++ caffe,其 forward() 返回值是一个字典类型其对应键值才是blob,output[‘prob’][0],而c++中直接返回blob,net_->output_blobs()[0];

slice()

1
2
3
4
5
b = a[i:j:s]这种格式呢,i,j与上面的一样,但s表示步进,缺省为1.

所以a[i:j:1]相当于a[i:j],当s<0时,i缺省时,默认为-1. j缺省时,默认为-len(a)-1.

所以a[::-1]相当于 a[-1:-len(a)-1:-1],也就是从最后一个元素到第一个元素复制一遍。所以你看到一个倒序的东东。

所以在Python中转换图像的通道顺序就很方便了,直接img_trans = img[::-1].
caffeCHW 来存放,所以第一维是C,因为img[0] 是 Red channel;img[1] 是 Green channel 倒序只是第一维导。注意的是python中图像的类型转换uint8:array.astype(np.uint8),Python默认的数字的数据类型为双精度浮点数

  1. 1
    2
    for layer_name, blob in net.blobs.iteritems():
    # 这样的foreach是对于键值map的,有两个输出一个是键一个是值。
  2. 1
    plt.imshow(img,cmap='gray',vmin=.vmax=) cmap 是显示类型,vmin,vmax 是归一化

pad()

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
padding = (((0, n ** 2 - data.shape[0]),
(0, 1), (0, 1)) # add some space between filters
+ ((0, 0),) * (data.ndim - 3)) # don't pad the last dimension (if there is one)

data = np.pad(data, padding, mode='constant', constant_values=1) # pad with ones (white)

data = np.pad(srs,padding,mode='',constant_values = (befor,after))

将srs进行补全padding是tuple 元组,((fst_dim_b,fst_dim_a),(snd_dim_b,snd_dim_a)).其中fst_dim_b是该维中前面去要填补的数量,fst_dim_a该维中后面去要填补的数量

constant_values = (befor,after),对应前面后面填充的数字。

#在数组A的边缘填充constant_values指定的数值

#(3,2)表示在A的第[0]轴填充(二维数组中,0轴表示行),即在0轴前面填充3个宽度的0,比如数组A中的95,96两个元素前面各填充了3个0;在后面填充2个0,比如数组A中的97,98两个元素后面各填充了2个0

#(2,3)表示在A的第[1]轴填充(二维数组中,1轴表示列),即在1轴前面填充2个宽度的0,后面填充3个宽度的0

np.pad(A,((3,2),(2,3)),'constant',constant_values = (0,0))
#constant_values表示填充值,且(before,after)的填充值等于(0,0)

array([[ 0, 0, 0, 0, 0, 0, 0], <-- array([[95, 96],
<-- [97, 98]])
[ 0, 0, 0, 0, 0, 0, 0], <--
[ 0, 0, 0, 0, 0, 0, 0], <--
[ 0, 0, 95, 96, 0, 0, 0], <--
[ 0, 0, 97, 98, 0, 0, 0], <--
[ 0, 0, 0, 0, 0, 0, 0], <--
[ 0, 0, 0, 0, 0, 0, 0]]) <--
  1. imshow()arraychannel是放在最后的

transpose

transpose会将调换通道序 注意非原地操作!!!
注意原地操作和非原地:
dif.transpose(1,0,2)是非原地的。
需要赋值才行。dif = dif.transpose.

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
data = data.reshape((4,4,8,8))
print( 'data='+ str(data[1,2,3,4]))
print('data_transpose='+str(data.transpose(0,2,1,3)[1,3,2,4]))
使用转置时,相近的','可以相乘起来,然后reshape 到一个更低维的张量。
不用在意transpose 后的细节,着重点应该放在维度本身的意义上。【数据转维、多维度一图可视化】

1.如:将solver.net['conv1'][0].data ->在样例中其是(20,1,5,5)的数据,要想将其转换在一张图片上进行Imshow
->先去前8通道。:
data = solver.net['conv1'][0].data[:8].squeeze() #其shape 为(8,5,5)
或者data = solver.net['conv1'][0].data[:80]
->padding = ((0,0),(0,1),(0,1))
data = np.pad(data,padding,mode='constant',constant_value = max(data))->注意constant_value的取值,需要是该data的最大值,
如果是很大的值,那么在之后imshow时,会全黑,应为默认的imshow是会归一化的。
->此时data.shape=(8,6,6)
->想画的图:一行八副图。->data = data.transpose(1,0,2)将第二维与第一维交换数据,第二维是行,所以交换后为:
(6,8,6)->第一维是行,有6个通道,每个通道有8副图的6个列通道。
->reshape(6,48):6个像素行,每一行有48个像素。
# solver.step(1)
# dif = solver.net.params['conv1'][0].diff[:, 0][:]
# maxx = np.max(dif)
# dif = np.pad(dif, ((0, 0), (0, 1), (0, 1)), mode='constant', constant_values=maxx if maxx!=0 else 1 )
# print 'maxx: '+str(maxx)
# print 'dif1: '+str(dif.shape)
# dif = dif.reshape(4,5,6,6)
# dif = dif.transpose(0,2,1,3)
# print 'dif2: '+str(dif.shape)
# plt.subplot(2, 1, 1)
# imshow(dif.reshape(24,30),cmap='gray');

caffe的一次训练流程:【caffe注意实项】

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
1. 使用SGDSolver直接load caffe网络。
1.prototxt都写好
2.solver = None #solver 每一个网络训练只能有一个。所以用时先None

3.solver = caffe.SGDSolver('mnist/lenet_auto_solver.prototxt')
#加载solver,按照proto中,其中需要注意的是test_nets可能会有多个,按照solver.proto中申明的来。

solver = caffe.SGDSolver('你的网络的lenet_solver.prototxt 文件'
#执行完上面的语句以后,网络的相应的权值与偏置会根据我们的定义进行赋值的;初始化,数据也会读入

3+.solver.net.copy_from(weights)从另外的模型中获得初始化

4.利用for 可以看见net 中的每一个blob.返回的是键值对。

5. solver.net.forward() 是train 的初始化
solver.test_net[0].forward() 是test的初始化

6.solver.step(1) ->反传一次
三个函数都是将批量大小(batch_size)的图片送到网络,
solver.net.forward() 和 solver.test_nets[0].forward()是将batch_size个图片送到网络中去,只有前向传播(Forward Propagation,FP),
solver.net.forward()作用于训练集,solver.test_nets[0].forward() 作用于测试集,一般用于获得测试集的正确率。
solver.step(1) 也是将batch_size个图片送到网络中去,不过 solver.step(1) 不仅有FP,
而且还有反向传播(Back Propagation,BP)!这样就可以更新整个网络的权值(weights),同时得到该batch的loss。
2. 使用caffe.Net()
e.g.
1.net = caffe.Net('prototxt.path', weights, caffe.TEST)
#'prototxt.path' prototxt的路径
# weights pretrained的模型路径
# caffe.TEST时态。
2.net.forward()
  1. 1
    2
    3
    net.params['name'][0](->w;[1]->bias;).data->data;diff->gradient
    solver.net.blobs['label'].data ->标记
    solver.test_net[0].blobs['label'].data

python 多图subplot:

1
2
3
4
5
6
7
8
plt.subplot(2, 1, 1)
imshow(dif.reshape(24,30),cmap='gray');
plt.show()
# axis('off')
plt.title('123')
plt.xlabel('X')
plt.ylabel('Y')
注意subplot是的图序号是从1开始的。

python 中获得图像句柄:

1
figure(figsize=(10, 2))

python 中三目运算符:

1
a = x if x>0 else y #当x大于0时返回x,否则返回y

python ///

3.0" / "就表示 浮点数除法,返回浮点结果;" // "表示整数除法。2.0/要看数据类型。或在最开始from __future__ import division

1
2
3
4
5
6
7
8
9
10
11
12
13
14
测试solver.net_test[0].blobs['label'].data
solver.net_test[0].forward()->初始化测试的数据,batch_size大小。由测试网络定义。
solver.net_test[0].forward(start='name') ->从**层开始可以不用load数据。
##
solver.test_nets[0].forward() #第1次 / 第101次 == 1次
for test_it in range(100): #读100次 /
solver.test_nets[0].forward()
print solver.test_nets[0].blobs['label'].data[:8]
solver.test_nets[0].forward(start='conv1')
print solver.test_nets[0].blobs['label'].data[:8]
output[it] = solver.test_nets[0].blobs['score'].data[:8]
##
如果从lmdb中读入数据读完一轮,那么将会循环。
这也时为什么在样例中可以一直读到不同轮次的output.

  1. np.array中支持array的每个item单独比较,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [2,1,3,1] == [2,0,0,1] ->[t,f,f,t]
    如果两个array不同大小,则是返回F
    a = np.array([[2,3],[1,2]])
    b = np.array([[0,3],[2,1]])
    print (a==b) ---> [[False True],[False False]]
    False = 0,True = 0;
    ..range = np.arange

    np.array中支持对整个list中所有数单独做运算:
    2*np.array([1,2,3]) -->[2,4,6]
  2. 一张图中画两个函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #fig, ax1 = plt.subplots()
    _, ax1 = subplots()
    ax2 = ax1.twinx() #公用x轴,ax1.twiny()公用y轴
    ax1.plot(arange(niter), train_loss) #x,y
    ax2.plot(test_interval * arange(len(test_acc)), test_acc, 'r') #x,y
    #在test_acc 中本来是每step(1),25次后记录对10000的正确率。所以实际上对应的迭代次数是
    25 50 75....250 次迭代所测试的结果。
    整个x粒度为10-250,第一个图像画loss,train_loss[it]记录了每次迭代的Loss
    但在test_acc[it]中记录的是2550...的测试结果,所以需要×25的x粒度。
  3. python 中imshow的补足:

    Imshow会将图像中的数据归一化显示出来,默认是minmax。imshow将数据标准化为最小和最大值。 您可以使用vmin和vmax参数或norm参数来控制(如果您想要非线性缩放)。
    如果imshow的不是连续的图像,维度长度太小其中会有过渡线性的填充不足,
    如果不想要线性渐变的填充的话可以使用interpolation='nearest',最近邻填充。
    

写solver.prototxt

需要:from caffe.proto import caffe_pb2

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
train_net_path = 'mnist/custom_auto_train.prototxt'
test_net_path = 'mnist/custom_auto_test.prototxt'
solver_config_path = 'mnist/custom_auto_solver.prototxt'
from caffe.proto import caffe_pb2
s = caffe_pb2.SolverParameter()
# Set a seed for reproducible experiments:
# this controls for randomization in training.
s.random_seed = 0xCAFFE
# Specify locations of the train and (maybe) test networks.
s.train_net = train_net_path
s.test_net.append(test_net_path)
s.test_interval = 500 # Test after every 500 training iterations.
s.test_iter.append(100) # Test on 100 batches each time we test.
s.max_iter = 10000 # no. of times to update the net (training iterations)
# EDIT HERE to try different solvers
# solver types include "SGD", "Adam", and "Nesterov" among others.
s.type = "SGD"
# Set the initial learning rate for SGD.
s.base_lr = 0.01 # EDIT HERE to try different learning rates
# Set momentum to accelerate learning by
# taking weighted average of current and previous updates.
s.momentum = 0.9
# Set weight decay to regularize and prevent overfitting
s.weight_decay = 5e-4
# Set `lr_policy` to define how the learning rate changes during training.
# This is the same policy as our default LeNet.
s.lr_policy = 'inv'
s.gamma = 0.0001
s.power = 0.75
# EDIT HERE to try the fixed rate (and compare with adaptive solvers)
# `fixed` is the simplest policy that keeps the learning rate constant.
# s.lr_policy = 'fixed'
# Display the current training loss and accuracy every 1000 iterations.
s.display = 1000
# Snapshots are files used to store networks we've trained.
# We'll snapshot every 5K iterations -- twice during training.
s.snapshot = 5000
s.snapshot_prefix = 'mnist/custom_net'
# Train on the GPU
s.solver_mode = caffe_pb2.SolverParameter.GPU
# Write the solver to a temporary file and return its filename.

1
2
3
4
5
6
image[image < 0], image[image > 255] = 0, 255
类似于matlab的find操作,但又有所不同。
返回的是bool数组,然后赋值。

image = np.round(image) //四舍五入
image = np.require(image, dtype=np.uint8)

python 中文件是否存在

1
2
3
4
5
6
7
8
python 中文件是否存在:assert os.path.exists(path_file)
weights = os.path.join()
1.如果各组件名首字母不包含’/’,则函数会自动加上   
2.如果各组件存在不含'/'的,则会被忽略掉,直到第一个/出现。
Path1 = 'home'
Path2 = '/develop'
Path3 = 'code'
Path20 = os.path.join(Path1,Path2,Path3) #Path20 = /develop\code 会舍弃非/开头的

load the txt in python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Python默认的数字的数据类型为双精度浮点数
np.loadtxt
( fname, #file_path
dtype=, #读入的数据类型
comments='#', #comment的是指, 如果行的开头为#就会跳过该行
delimiter=None, #分隔符txt中数据,如','分割。
converters=None, #converters参数, 这个是对数据进行预处理的参数,

#我们可以先定义一个函数
# converters = {0:add_one}这里的converters是一个字典, 表示第零列使用函数add_one来进行预处理

usecols=(),
skiprows=0, #skiprows是指跳过前1行, 如果设置skiprows=2, 就会跳过前两行
unpack=False,#unpack是指会把每一列当成一个向量输出, 而不是合并在一起。
ndmin=0
)

‘string’.join()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
_str.join(src)用于以特定的分隔符(_str)分隔源变量(src),将其作为新的元素加入到一个列表中
_mail_from = 'hehuLi'
_mail_to = 'lihao'
_mail_text ='ni hao'
body = "\r\n".join(
("From : %s" %_mail_from, #%不同于.format(),format必须要键值对。
"to : %s" %_mail_to,
"",
_mail_text)
)
% 的用法:
print ("pi的值是%s"%pi)
print("%6.3f" % 2.3)
# 第一个"%"后面的内容为显示的格式说明,6为显示宽度,3为小数点位数,f为浮点数类型
# 第二个"%"后面为显示的内容来源,输出结果右对齐,2.300长度为5,故前面有一空格

临时文件的创建:

1
2
empfile.NamedTemporaryFile(delete=False)
f.write(str(n.to_proto()))

caffeDummyData层是用来产生数的,就像np.random一样产生一些随机数。

程序解析:

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
def run_solvers(niter, solvers, disp_interval=10):
"""Run solvers for niter iterations,
returning the loss and accuracy recorded each iteration.
`solvers` is a list of (name, solver) tuples."""
blobs = ('loss', 'acc')
loss, acc = ({name: np.zeros(niter) for name, _ in solvers}
for _ in blobs)
for it in range(niter):
for name, s in solvers:
s.step(1) # run a single SGD step in Caffe
loss[name][it], acc[name][it] = (s.net.blobs[b].data.copy()
for b in blobs)
if it % disp_interval == 0 or it + 1 == niter:
loss_disp = '; '.join('%s: loss=%.3f, acc=%2d%%' %
(n, loss[n][it], np.round(100*acc[n][it]))
for n, _ in solvers)
print '%3d) %s' % (it, loss_disp)
# Save the learned weights from both nets.
weight_dir = tempfile.mkdtemp()
weights = {}
for name, s in solvers:
filename = 'weights.%s.caffemodel' % name
weights[name] = os.path.join(weight_dir, filename)
s.net.save(weights[name])
return loss, acc, weights

该函数功能是对两个已经定义的solver进行细节处理:

solvers有两个网络,是在caffe/02-fine-tuning 中的例子。其中一个是没有初始化赋值的model,一个是初始化了的model.

1
2
3
4
5
6
7
8
9
10
11
style_solver_filename = solver(style_net(train=True))
style_solver = caffe.get_solver(style_solver_filename)
style_solver.net.copy_from(weights)

# For reference, we also create a solver that isn't initialized from
# the pretrained ImageNet weights.
scratch_style_solver_filename = solver(style_net(train=True))
scratch_style_solver = caffe.get_solver(scratch_style_solver_filename)
style_solver是初始化了的:style_solver.net.copy_from(weights)
在caffe中也可以使用caffe.Net("prototxt",weights)来初始化。
也可以用style_solver.net.copy_from(weights),weights caffemodel的路径

3.

1
2
blobs = ('loss', 'acc') #将要取出的模型的blob的名字。
#格式为:s.net.blobs['loss'].data[0] ->

4.

1
2
3
4
loss, acc = ({name: np.zeros(niter) for name, _ in solvers}
for _ in blobs)

list_a, list_b = ({} for _ in blobs),可以生成两个list。