caffe
कस्टम पायथन लेयर्स
खोज…
परिचय
यह ट्यूटोरियल पायथन का उपयोग करके कैफ के लिए एक सरल कस्टम परत बनाने के चरणों के माध्यम से मार्गदर्शन करेगा। इसके अंत तक, कस्टम परतों के कुछ उदाहरण हैं। आमतौर पर आप अपनी कार्यक्षमता के लिए एक कस्टम लेयर बनाते हैं जो कैफ़ में उपलब्ध नहीं है, इसे अपनी आवश्यकताओं के लिए ट्यूनिंग करें।
अजगर कस्टम लेयर बनाना आपके नेटवर्क में कुछ ओवरहेड जोड़ता है और शायद C ++ कस्टम लेयर जितना कुशल नहीं है। हालांकि, इस तरह, आपको अपनी नई परत के साथ पूरे कैफ को संकलित नहीं करना होगा।
पैरामीटर
| पैरामीटर | विवरण |
|---|---|
| ऊपर | आपकी परत के शीर्ष के साथ एक सरणी। शीर्ष [i] .data का उपयोग करके उस तक पहुंच डेटा, जहां मैं एक विशिष्ट बूँद का सूचकांक है |
| तल | आपकी परत के निचले हिस्से के साथ एक सरणी। नीचे [i] .data का उपयोग करके उस तक पहुंच डेटा, जहां मैं एक विशिष्ट बूँद का सूचकांक है |
टिप्पणियों
- पाइथन परत के साथ कैफ का निर्माण
Caffe को WITH_PYTHON_LAYER विकल्प के साथ संकलित करने की आवश्यकता है:
WITH_PYTHON_LAYER=1 make && make pycaffe
- मुझे क्लास फाइल कहाँ बचानी चाहिए?
आपके पास दो विकल्प हैं (कम से कम मुझे पता है कि)। या तो आप कस्टम लेयर फ़ाइल को उसी फ़ोल्डर में सहेज सकते हैं, जैसे आप कैफ कमांड को चलाने जा रहे हैं (शायद आपकी प्रोटोटेक्स्ट फाइलें कहां होंगी)। एक अन्य तरीका, मेरा पसंदीदा भी, एक फ़ोल्डर में अपने सभी कस्टम लेयर को सहेजना और इस फ़ोल्डर को अपने PYTHONPATH में जोड़ना है।
संदर्भ
लेयर टेम्पलेट
import caffe
class My_Custom_Layer(caffe.Layer):
def setup(self, bottom, top):
pass
def forward(self, bottom, top):
pass
def reshape(self, bottom, top):
pass
def backward(self, bottom, top):
pass
इसलिए याद रखने वाली महत्वपूर्ण बातें:
- आपकी कस्टम लेयर को caffe से विरासत में प्राप्त करना होता है। इसलिए ( कैफ आयात करना न भूलें);
- आपको निम्नलिखित चार तरीकों को परिभाषित करना होगा: सेटअप , फॉरवर्ड , रिशेप और बैकवर्ड ;
- सभी तरीकों में एक शीर्ष और एक निचला पैरामीटर होता है, जो कि इनपुट को स्टोर करने वाली बूँदें हैं और आउटपुट आपके लेयर पर जाता है। आप इसे शीर्ष [i] .डेटा या नीचे [i] .data का उपयोग करके एक्सेस कर सकते हैं, जहां मैं एक से अधिक ऊपरी या निचले ब्लॉब के मामले में बूँद का सूचकांक है।
- सेटअप विधि
सेटअप विधि को निष्पादन के जीवनकाल के दौरान एक बार कहा जाता है, जब कैफ सभी परतों को त्वरित कर रहा है। यह वह जगह है जहां आप मापदंडों को पढ़ेंगे, निश्चित आकार के बफ़र्स को तुरंत लिखेंगे।
- पुनर्वसन विधि
आरंभीकरण / सेटअप के लिए reshape विधि का उपयोग करें जो नीचे बूँद (परत इनपुट) आकार पर निर्भर करता है। इसे एक बार कहा जाता है जब नेटवर्क को त्वरित किया जाता है।
- आगे की विधि
फॉरवर्ड विधि को प्रत्येक इनपुट बैच के लिए कहा जाता है और वह है जहां आपके अधिकांश तर्क होंगे।
- पिछड़ी विधि
नेटवर्क के बैकवर्ड पास के दौरान बैकवर्ड पद्धति को कहा जाता है। उदाहरण के लिए, एक कनवल्शन-जैसी परत में, यह वह जगह होगी जहां आप ग्रेडिएंट्स की गणना करेंगे। यह वैकल्पिक है (एक परत केवल आगे हो सकती है)।
प्रोटोटेक्स्ट टेम्पलेट
ठीक है, तो अब आपके पास अपनी परत डिज़ाइन की गई है! इसे आप अपनी .prototxt फ़ाइल में कैसे परिभाषित करते हैं:
layer {
name: "LayerName"
type: "Python"
top: "TopBlobName"
bottom: "BottomBlobName"
python_param {
module: "My_Custom_Layer_File"
layer: "My_Custom_Layer_Class"
param_str: '{"param1": 1,"param2":True, "param3":"some string"}'
}
include{
phase: TRAIN
}
}
महत्वपूर्ण टिप्पणी:
- प्रकार अजगर होना चाहिए;
- आपके पास कम से कम मॉड्यूल और परत मापदंडों के साथ एक python_param शब्दकोश होना चाहिए;
- मॉड्यूल उस फ़ाइल को संदर्भित करता है जहां आपने अपनी परत ( .py के बिना) लागू की थी;
- परत आपके वर्ग के नाम को संदर्भित करता है;
- आप param_str का उपयोग करके परत को पैरामीटर पास कर सकते हैं (उन तक पहुँचने में अधिक)
- किसी भी अन्य परत की तरह, आप यह परिभाषित कर सकते हैं कि आप किस चरण में सक्रिय होना चाहते हैं (उदाहरण देखें कि आप वर्तमान चरण की जांच कैसे कर सकते हैं);
परत के लिए पैरामीटर पारित करना
आप param_str का उपयोग करके प्रोटोटेक्स्ट में परत मापदंडों को परिभाषित कर सकते हैं। एक बार जब आप इसे कर लेते हैं, तो यहां एक उदाहरण दिया गया है कि आप परत वर्ग के अंदर इन पिरामिडों का उपयोग कैसे करते हैं:
def setup(self, bottom, top):
params = eval(self.param_str)
param1 = params["param1"]
param2 = params.get('param2', False) #I usually use this when fetching a bool
param3 = params["param3"]
#Continue with the setup
# ...
उपाय उपाय
इस उदाहरण में हम एक "माप" परत डिजाइन करेंगे, जो प्रशिक्षण के दौरान द्विआधारी समस्या के लिए सटीकता और एक भ्रम मैट्रिक्स को आउटपुट करता है और परीक्षण / सत्यापन के दौरान सटीकता, झूठी सकारात्मक दर और झूठी नकारात्मक दर। हालांकि कैफ में पहले से ही एक सटीकता की परत है, कभी-कभी आप एफ-माप की तरह कुछ और चाहते हैं।
यह मेरी नापसंद है मेरी कक्षा की परिभाषा के साथ:
#Remark: This class is designed for a binary problem, where the first class would be the 'negative'
# and the second class would be 'positive'
import caffe
TRAIN = 0
TEST = 1
class Measure_Layer(caffe.Layer):
#Setup method
def setup(self, bottom, top):
#We want two bottom blobs, the labels and the predictions
if len(bottom) != 2:
raise Exception("Wrong number of bottom blobs (prediction and label)")
#And some top blobs, depending on the phase
if self.phase = TEST and len(top) != 3:
raise Exception("Wrong number of top blobs (acc, FPR, FNR)")
if self.phase = TRAIN and len(top) != 5:
raise Exception("Wrong number of top blobs (acc, tp, tn, fp and fn)")
#Initialize some attributes
self.TPs = 0.0
self.TNs = 0.0
self.FPs = 0.0
self.FNs = 0.0
self.totalImgs = 0
#Forward method
def forward(self, bottom, top):
#The order of these depends on the prototxt definition
predictions = bottom[0].data
labels = bottom[1].data
self.totalImgs += len(labels)
for i in range(len(labels)): #len(labels) is equal to the batch size
pred = predictions[i] #pred is a tuple with the normalized probability
#of a sample i.r.t. two classes
lab = labels[i]
if pred[0] > pred[1]:
if lab == 1.0:
self.FNs += 1.0
else:
self.TNs += 1.0
else:
if lab == 1.0:
self.TPs += 1.0
else:
self.FPs += 1.0
acc = (self.TPs + self.TNs) / self.totalImgs
try: #just assuring we don't divide by 0
fpr = self.FPs / (self.FPs + self.TNs)
except:
fpr = -1.0
try: #just assuring we don't divide by 0
fnr = self.FNs / (self.FNs + self.TPs)
except:
fnr = -1.0
#output data to top blob
top[0].data = acc
if self.phase == TRAIN:
top[1].data = self.TPs
top[2].data = self.TNs
top[3].data = self.FPs
top[4].data = self.FNs
elif self.phase == TEST:
top[1].data = fpr
top[2].data = fnr
def reshape(self, bottom, top):
"""
We don't need to reshape or instantiate anything that is input-size sensitive
"""
pass
def backward(self, bottom, top):
"""
This layer does not back propagate
"""
pass
और यह इसके साथ एक प्रोटोटाइप का एक उदाहरण है:
layer {
name: "metrics"
type: "Python"
top: "Acc"
top: "TPs"
top: "TNs"
top: "FPs"
top: "FNs"
bottom: "prediction" #let's supose we have these two bottom blobs
bottom: "label"
python_param {
module: "measureLayer"
layer: "Measure_Layer"
}
include {
phase: TRAIN
}
}
layer {
name: "metrics"
type: "Python"
top: "Acc"
top: "FPR"
top: "FNR"
bottom: "prediction" #let's supose we have these two bottom blobs
bottom: "label"
python_param {
module: "measureLayer"
layer: "Measure_Layer"
}
include {
phase: TEST
}
}
डेटा लेयर
यह उदाहरण एक कस्टम डेटा परत है, जो छवि पथों के साथ एक पाठ फ़ाइल प्राप्त करता है, छवियों के एक बैच को लोड करता है और उन्हें प्रीप्रोसेस करता है। बस एक त्वरित टिप, कैफ में पहले से ही डेटा परतों की एक बड़ी श्रृंखला है और शायद एक कस्टम परत सबसे कुशल तरीका नहीं है यदि आप बस कुछ सरल चाहते हैं।
मेरा dataLayer.py कुछ इस तरह हो सकता है:
import caffe
class Custom_Data_Layer(caffe.Layer):
def setup(self, bottom, top):
# Check top shape
if len(top) != 2:
raise Exception("Need to define tops (data and label)")
#Check bottom shape
if len(bottom) != 0:
raise Exception("Do not define a bottom.")
#Read parameters
params = eval(self.param_str)
src_file = params["src_file"]
self.batch_size = params["batch_size"]
self.im_shape = params["im_shape"]
self.crop_size = params.get("crop_size", False)
#Reshape top
if self.crop_size:
top[0].reshape(self.batch_size, 3, self.crop_size, self.crop_size)
else:
top[0].reshape(self.batch_size, 3, self.im_shape, self.im_shape)
top[1].reshape(self.batch_size)
#Read source file
#I'm just assuming we have this method that reads the source file
#and returns a list of tuples in the form of (img, label)
self.imgTuples = readSrcFile(src_file)
self._cur = 0 #use this to check if we need to restart the list of imgs
def forward(self, bottom, top):
for itt in range(self.batch_size):
# Use the batch loader to load the next image.
im, label = self.load_next_image()
#Here we could preprocess the image
# ...
# Add directly to the top blob
top[0].data[itt, ...] = im
top[1].data[itt, ...] = label
def load_next_img(self):
#If we have finished forwarding all images, then an epoch has finished
#and it is time to start a new one
if self._cur == len(self.imgTuples):
self._cur = 0
shuffle(self.imgTuples)
im, label = self.imgTuples[self._cur]
self._cur += 1
return im, label
def reshape(self, bottom, top):
"""
There is no need to reshape the data, since the input is of fixed size
(img shape and batch size)
"""
pass
def backward(self, bottom, top):
"""
This layer does not back propagate
"""
pass
और प्रोटोक्सट इस तरह होगा:
layer {
name: "Data"
type: "Python"
top: "data"
top: "label"
python_param {
module: "dataLayer"
layer: "Custom_Data_Layer"
param_str: '{"batch_size": 126,"im_shape":256, "crop_size":224, "src_file": "path_to_TRAIN_file.txt"}'
}
}