GitHub コードアドレス: https://github.com/HansRen1024/Use-Python-to-call-Caffe-module
前言#
この一連のブログを書く前に本当に長い間考えました。どう始めればいいのか分からない感じがしました。やはり実力が足りないので、こういう時こそ無理にでも書かなければなりません。頑張ります!
まずは各関数を個別に出して、最後に完全なコードを出します。各関数で個別に使用するモジュールは、関数内で個別に読み込むことで、コードを独立して実行しやすくします。
import caffe は全体で共通のモジュールなので、各関数で個別に読み込む必要はありません。
一、caffe モジュールの読み込み#
将来的に便利に使うために、caffe モジュールを python のデフォルトパスに置きます。これで任意のディレクトリから caffe モジュールを読み込むことができます。
caffe のコンパイルが成功した後に実行します:
make pycaffe
sudo cp -r python/caffe/ /usr/local/lib/python/dist-packages # 友人によってはパスがsite-packagesの場合もありますので、これは人によります。
この時点で python を実行し、import caffe を行うと、caffe の動的ライブラリが見つからないというメッセージが表示されます。
$CAFFE_ROOT/.build_release/lib/ を環境変数に追加することができます。
または、その動的ライブラリを /usr/lib/ または /usr/local/lib ディレクトリにコピーすることもできます。
この時点で、任意のディレクトリから python を実行し、import caffe ができるはずです。
二、トレーニングとテストの prototxt ファイルを生成する#
ネットワーク構造ファイルを生成する方法を 2 つ見つけましたが、以下の NetSpec () インスタンス n を定義する方法が比較的良いので、まずこの方法を書きます。この方法で生成されたファイル内では、各層の名前と出力 blob の名前は等号の前で定義された n のメソッドです。
def lenet(lmdb, batch_size, include_acc=False):
from caffe import layers as L
from caffe import params as P
n = caffe.NetSpec()
# 各層内の具体的なパラメータは、既存のprototxtファイルを参照してください。ここに書いたものは全てではありません。
n.data, n.label = L.Data(batch_size=batch_size, backend=P.Data.LMDB, source=lmdb,
transform_param=dict(scale=1./255), ntop=2) # ntopは2つの出力を示します
n.conv1 = L.Convolution(n.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
n.pool1 = L.Pooling(n.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.conv2 = L.Convolution(n.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.ip1 = L.InnerProduct(n.pool2, num_output=500, weight_filler=dict(type='xavier'))
n.relu1 = L.ReLU(n.ip1, in_place=True)
n.ip2 = L.InnerProduct(n.relu1, num_output=10, weight_filler=dict(type='xavier'))
n.loss = L.SoftmaxWithLoss(n.ip2, n.label)
if include_acc: # テストファイルを生成する際には、精度を計算する層が必要です。
n.acc = L.Accuracy(n.ip2, n.label)
return n.to_proto() # 注意:ここでのto_proto()はパラメータを持たないことに注意してください。
def write_lenet():
with open('./doc/train_lenet.prototxt','w') as f:
f.write(str(lenet('./doc/mnist_train_lmdb', 64)))
with open('./doc/test_lenet.prototxt', 'w') as f:
f.write(str(lenet('./doc/mnist_test_lmdb', 100, True)))
三、deploy ファイルを生成する#
ここではネットワーク構造ファイルを生成する 2 つ目の方法を示しますが、この方法はあまり推奨しません。実際、deploy は上で生成したファイルをそのまま変更すれば簡単です。
def deploy():
from caffe import layers as L
from caffe import params as P
from caffe import to_proto
# deployファイルにはデータ層がありません
conv1 = L.Convolution(bottom='data', kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
pool1 = L.Pooling(conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
conv2 = L.Convolution(pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
pool2 = L.Pooling(conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
ip1 = L.InnerProduct(pool2, num_output=500, weight_filler=dict(type='xavier'))
relu1 = L.ReLU(ip1, in_place=True)
ip2 = L.InnerProduct(relu1, num_output=10, weight_filler=dict(type='xavier'))
prob = L.Softmax(ip2) # 最後の層ではlossを計算せず、確率を出力します。
return to_proto(prob) # ここではパラメータを持つ必要があります
def write_deploy():
with open('doc/deploy_lenet.prototxt', 'w') as f:
f.write('name: "Lenet"\n')
f.write('input: "data"\n')
f.write('input_dim: 1\n')
f.write('input_dim: 3\n')
f.write('input_dim: 28\n')
f.write('input_dim: 28\n')
f.write(str(deploy()))
四、solver ファイルを生成する#
方法 1 は辞書を使用して生成します:
def solver_dict():
solver_file='doc/solver_lenet.prototxt'
sp={}
sp['train_net']='"doc/train_lenet.prototxt"'
sp['test_net']='"doc/test_lenet.prototxt"'
sp['test_iter']='100'
sp['test_interval']='500'
sp['display']='100'
sp['max_iter']='10000'
sp['base_lr']='0.01'
sp['lr_policy']='"inv"'
sp['gamma']='0.0001'
sp['power']='0.75'
sp['momentum']='0.9'
sp['weight_decay']='0.0005'
sp['snapshot']='5000'
sp['snapshot_prefix']='"models/lenet"'
sp['solver_mode']='GPU'
sp['solver_type']='SGD'
sp['device_id']='0'
with open(solver_file, 'w') as f:
for key, value in sp.items():
if not(type(value) is str):
raise TypeError('すべてのsolverパラメータは文字列でなければなりません')
f.write('%s: %s\n' %(key, value))
方法 2 は caffe モジュールを呼び出して生成しますが、この方法で生成されたファイルには小数部分にわずかな損失があります。処女座の強迫観念が出てしまいました!
def solver_caffe():
from caffe.proto import caffe_pb2
s = caffe_pb2.SolverParameter()
solver_file='doc/solver_lenet.prototxt'
s.train_net = 'doc/train_lenet.prototxt'
s.test_net.append('doc/test_lenet.prototxt')
s.test_interval = 500
s.test_iter.append(100)
s.display = 100
s.max_iter = 10000
s.base_lr = 0.01
s.lr_policy = "inv"
s.gamma = 0.0001
s.power = 0.75
s.momentum = 0.9
s.weight_decay = 0.0005
s.snapshot = 5000
s.snapshot_prefix = "models/lenet"
s.type = "SGD"
s.solver_mode = caffe_pb2.SolverParameter.GPU
with open(solver_file, 'w') as f:
f.write(str(s))
五、完全なコード:#
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Sat Jul 29 11:16:29 2017
@author: hans
"""
import caffe
def lenet(lmdb, batch_size, include_acc=False):
from caffe import layers as L
from caffe import params as P
n = caffe.NetSpec()
n.data, n.label = L.Data(batch_size=batch_size, backend=P.Data.LMDB, source=lmdb,
transform_param=dict(scale=1./255), ntop=2)
n.conv1 = L.Convolution(n.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
n.pool1 = L.Pooling(n.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.conv2 = L.Convolution(n.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.ip1 = L.InnerProduct(n.pool2, num_output=500, weight_filler=dict(type='xavier'))
n.relu1 = L.ReLU(n.ip1, in_place=True)
n.ip2 = L.InnerProduct(n.relu1, num_output=10, weight_filler=dict(type='xavier'))
n.loss = L.SoftmaxWithLoss(n.ip2, n.label)
if include_acc:
n.acc = L.Accuracy(n.ip2, n.label)
return n.to_proto()
def write_lenet():
with open('./doc/train_lenet.prototxt','w') as f:
f.write(str(lenet('./doc/mnist_train_lmdb', 64)))
with open('./doc/test_lenet.prototxt', 'w') as f:
f.write(str(lenet('./doc/mnist_test_lmdb', 100, True)))
def deploy():
from caffe import layers as L
from caffe import params as P
from caffe import to_proto
conv1 = L.Convolution(bottom='data', kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
pool1 = L.Pooling(conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
conv2 = L.Convolution(pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
pool2 = L.Pooling(conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
ip1 = L.InnerProduct(pool2, num_output=500, weight_filler=dict(type='xavier'))
relu1 = L.ReLU(ip1, in_place=True)
ip2 = L.InnerProduct(relu1, num_output=10, weight_filler=dict(type='xavier'))
prob = L.Softmax(ip2)
return to_proto(prob)
def write_deploy():
with open('doc/deploy_lenet.prototxt', 'w') as f:
f.write('name: "Lenet"\n')
f.write('input: "data"\n')
f.write('input_dim: 1\n')
f.write('input_dim: 3\n')
f.write('input_dim: 28\n')
f.write('input_dim: 28\n')
f.write(str(deploy()))
def solver_dict():
solver_file='doc/solver_lenet.prototxt'
sp={}
sp['train_net']='"doc/train_lenet.prototxt"'
sp['test_net']='"doc/test_lenet.prototxt"'
sp['test_iter']='100'
sp['test_interval']='500'
sp['display']='100'
sp['max_iter']='10000'
sp['base_lr']='0.01'
sp['lr_policy']='"inv"'
sp['gamma']='0.0001'
sp['power']='0.75'
sp['momentum']='0.9'
sp['weight_decay']='0.0005'
sp['snapshot']='5000'
sp['snapshot_prefix']='"models/lenet"'
sp['solver_mode']='GPU'
sp['solver_type']='SGD'
sp['device_id']='0'
with open(solver_file, 'w') as f:
for key, value in sp.items():
if not(type(value) is str):
raise TypeError('すべてのsolverパラメータは文字列でなければなりません')
f.write('%s: %s\n' %(key, value))
def solver_caffe():
from caffe.proto import caffe_pb2
s = caffe_pb2.SolverParameter()
solver_file='doc/solver_lenet.prototxt'
s.train_net = 'doc/train_lenet.prototxt'
s.test_net.append('doc/test_lenet.prototxt')
s.test_interval = 500
s.test_iter.append(100)
s.display = 100
s.max_iter = 10000
s.base_lr = 0.01
s.lr_policy = "inv"
s.gamma = 0.0001
s.power = 0.75
s.momentum = 0.9
s.weight_decay = 0.0005
s.snapshot = 5000
s.snapshot_prefix = "models/lenet"
s.type = "SGD"
s.solver_mode = caffe_pb2.SolverParameter.GPU
with open(solver_file, 'w') as f:
f.write(str(s))
def train():
caffe.set_device(0)
caffe.set_mode_gpu()
solver = caffe.SGDSolver('doc/solver_lenet.prototxt')
solver.solve()
if __name__ == '__main__':
write_lenet()
# write_deploy()
# solver_dict()
# solver_caffe()
# train()