Dies ist der 4. Beitrag zu Qiita. (Artikel 4)
Als ich von letztes Mal fortfuhr, während ich nnabla verwendete, fühlte ich mich wie "Ich wünschte, ich hätte diese Art von Informationen in Qiita" Zusammenfassung dessen, was ich in der nnabla-Referenz gefunden habe und dir ()
(Standard-Python-Funktion, die Mitgliedsvariablen und Funktionen von Argumenten zurückgibt) Ich werde.
-OS: macOS Catalina (Version 10.15.1) ・ Python: 3.5.4 ・ Nnabla: 1.3.0
Verwenden Sie dieses Mal aus Nnablas geschultem Modell MobileNet_v1 wie folgt.
article4_add_quantization_for_network.py
import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF
from nnabla.models.imagenet import MobileNet
if __name__ == "__main__":
# [load network]
mobilenet = MobileNet()
nnp = mobilenet.nnp
net = nnp.get_network('Runtime', batch_size=1)
y = net.outputs['y\'']
nnabla.models
bietet trainierte Modelle als Netzwerk von nnabla. Dieses Mal werden wir mobilet_v1 darin verwenden.mobilet = MobileNet ()
herunter.nnp = mobilet.nnp
enthält mobilet in der Variablen nnp
, um das eigene Dateiformat" .nnp "von nnabla zu lesen.net = nnp.get_network ('Validation', batch_size = 1)
.y'
von y = net.outputs ['y \' ']
erhalten. Dies wird später verwendet, um den Vorgang zu überprüfen. Es hat nichts mit dem zu tun, was Sie diesmal versuchen.Fügen Sie jeder oben erhaltenen Aktivierung, Pooling und Affiliate (Identifizierungsausgabe) von mobilet_v1 eine Quantisierungsschicht hinzu. Der tatsächliche Code ist unten.
article4_add_quantization_for_network.py
class AddQuantizeLayer:
def __init__(self, _net):
self.net = _net
def add_quantize_layer_all(self):
# [quantize]
count = 0
for key in self.net.variables:
var = self.net.variables[key]
func = var.parent
if type(func) != type(None):
if func.info.type_name in ['ReLU', 'AveragePooling', 'Affine']:
count = self.add_quantize_layer_one(var, count)
def add_quantize_layer_one(self, _var, _count):
var_out_cur = _var.function_references[0].outputs[0]
# [quantize]
q_out = PF.min_max_quantize(_var, ql_min=0, ql_max=255, x_min_max=True, name='MinMaxQuantize_{}'.format(_count))
# [redefine function]
var_out_new = self.redefine_layer(var_out_cur.parent, q_out)
var_out_cur.rewire_on(var_out_new)
return _count + 1
@staticmethod
def redefine_layer(_func, _input):
if _func.info.type_name == 'DepthwiseConvolution':
return F.depthwise_convolution(_input, *_func.inputs[1:], **_func.info.args)
elif _func.info.type_name == 'Convolution':
return F.convolution(_input, *_func.inputs[1:], **_func.info.args)
elif _func.info.type_name == 'AveragePooling':
return F.average_pooling(_input, **_func.info.args)
elif _func.info.type_name == 'Affine':
return F.affine(_input, *_func.inputs[1:], **_func.info.args)
elif _func.info.type_name == 'Softmax':
return F.softmax(_input, **_func.info.args)
else:
print('[error] redefine_layer()')
print('_func is unexpected layer.')
print('_func.info.type_name = {}'.format(_func.info.type_name))
exit(0)
# [quantize]
AddQuantizeLayer_class = AddQuantizeLayer(net)
AddQuantizeLayer_class.add_quantize_layer_all()
Die Funktionsprüfung wurde unten durchgeführt.
article4_add_quantization_for_network.py
def print_func(f):
print('{}'.format(f.name))
print('----- before -----')
y.visit(print_func)
print('')
# [quantize]
AddQuantizeLayer_class = AddQuantizeLayer(net)
AddQuantizeLayer_class.add_quantize_layer_all()
print('----- after -----')
y.visit(print_func)
print('')
Da die Ausgabe lang ist, werden einige Teile weggelassen, aber in der folgenden Form. Zur Änderung wird "MinMaxQuantize" (Quantisierungsschicht) nach "ReLU", "AveragePooling", "Affine" hinzugefügt.
----- before -----
ImageAugmentation
MulScalar
AddScalar
Convolution
BatchNormalization
ReLU
DepthwiseConvolution
BatchNormalization
ReLU
Convolution
...(Folgendes wird weggelassen)...
----- after -----
ImageAugmentation
MulScalar
AddScalar
Convolution
BatchNormalization
ReLU
MinMaxQuantize
DepthwiseConvolution
BatchNormalization
ReLU
MinMaxQuantize
Convolution
...(Folgendes wird weggelassen)...
self.net.variables
ist das Diktat
aller Netzwerkvariablen. AddQuantizeLayer.add_quantize_layer_all
verwendet dies, um jede Variable im Netzwerk zu überprüfen. Hier erhält var.parent
die Ebene, die die Variable ausgibt, und func.info.type_name
erhält den Namen dieser Ebene.wird endlich die Verbindung von
...-> MinMaxQuantize-> Convolution-> ...` hergestellt. (Ich möchte es in der Abbildung erklären.)AddQuantizeLayer.redefine_layer
definiert genau dieselbe Ebene wie die vorhandene, um das obige Problem zu lösen. _input
ist die quantisierte Variable ( nn.Variable
), _func.inputs [1:]
ist die andere Eingabevariable (nn.Variable
) (diesmal der Koeffizient wie conv), _func. info.args
ist das andere Argument (Schritt, Polsterung usw.).Unter Verwendung des Inhalts, der bis zu Letztes Mal veröffentlicht wurde, wurde das Hinzufügen einer Quantisierungsschicht zu einem vorhandenen Netzwerk vorgestellt. Es ist unentschlossen, was das nächste Mal gepostet werden soll.
Recommended Posts