noisy student
ist eine Methode zum Starten von SOTA mit Imagenet.
Normalerweise müssen Menschen beim Erhöhen der Daten und beim Umschulen Lehrerdaten erstellen, aber "lauter Schüler" sammelt trotzdem Daten, leitet sie an das aktuelle Modell weiter und trainiert sie als temporäre Lehrerdaten neu, um die Genauigkeit zu verbessern. Da es angehoben werden kann, benötigen Sie keine Zeit, um Lehrerdaten zu erstellen. Genau genommen müssen wir Daten sammeln, die einem der Originaletiketten entsprechen, aber ich bin dankbar, dass die Leute keinen Lehrer brauchen.
Weitere Informationen finden Sie auf der folgenden Website.
Kommentar: Gründlicher Kommentar zum neuesten SoTA-Modell "Noisy Student" zur Bilderkennung! Artikel: Selbsttraining mit Noisy Student verbessert die ImageNet-Klassifizierung
Jeder, den ich mache, ist nicht so schwierig, deshalb werde ich in diesem Artikel versuchen, ihn mit Imagenet zu reproduzieren. Ich dachte, aber es braucht viel Zeit, um mit meinen PC-Fähigkeiten zu lernen, also habe ich Experimente mit resnet50 und cifar10 versucht. Ich hoffe, Sie haben es als Referenz für das Verfahren und die Implementierungsmethode gelesen.
tensorflow 1.15.0
keras 2.3.1
Python 3.7.6
numpy 1.18.1
core i7
GTX1080ti
Das Verfahren für "lauter Schüler" ist wie folgt.
Zitat: Selbsttraining mit Noisy Student verbessert die ImageNet-Klassifizierung
Auf Japanisch zusammenfassen
Was ist ** Lärm ** hier?
ist. Ich werde sie bei der Implementierung kurz erläutern.
Rand Augmentation Verbessern Sie die Genauigkeit des Bilderkennungsmodells mit nur zwei Zeilen! ?? Erklärung der neuen automatischen Optimierungsmethode "Rand Augment" zur Datenerweiterung! Das Obige ist leicht zu verstehen. Bereiten Sie zusammenfassend X Arten der Datenerweiterung vor
das ist alles. Es ist einfach. Die Arbeit des lauten Schülers nimmt N = 2 und M = 27 an. In meiner Implementierung habe ich diesmal N = 2 und M = 10 gesetzt. Der Grund dafür ist, dass cifar10 eine kleine Bildgröße hat, daher ist es besser, zu viel Rauschen anzuwenden.
Dropout Das ist berühmt, also werde ich es weglassen. 0,5 wird in das Papier eines lauten Schülers übernommen.
Stochastic depth [Survey]Deep Networks with Stochastic Depth Wenn Sie mehr wissen möchten, lesen Sie bitte die obige Erklärung.
Zitat: Tiefe Netzwerke mit stochastischer Tiefe
Ich werde kurz anhand des obigen Bildes erklären.
Zunächst besteht die Grundidee darin, die Ausgabe von resnet nur auf den Teil zu beschränken, der wahrscheinlich übersprungen wird. Dann wird die Wahrscheinlichkeit linear erhöht, wenn die Schicht tiefer wird. In der lauten Schülerarbeit beträgt die letzte Schicht 0,8.
Wenn gefolgert wird, wird die Wahrscheinlichkeit mit der Ausgabe jedes Resnet-Blocks multipliziert.
Die erste Phase war lang, aber ich würde sie gerne umsetzen. Hier werde ich das Verfahren überprüfen.
Ich werde die Implementierung in dieser Reihenfolge erklären.
Dies ist nur ein häufiges Klassifizierungsproblem. Ich wollte ein effizientes Netz für das Modell vorbereiten, habe es aber mit resnet50 versucht, um den Implementierungsaufwand zu sparen. Bitte beachten Sie, dass die Grundstruktur mit resnet50 identisch ist, die Bildgröße jedoch nicht zu klein sein sollte. Wir reduzieren die Anzahl der Schritte auf 2.
cifar10_resnet50.py
from keras.datasets import cifar10
from keras.utils.np_utils import to_categorical
#Bereiten Sie den cifar10-Datensatz vor
(x_train_10,y_train_10),(x_test_10,y_test_10)=cifar10.load_data()
#Lehrerdaten eins-Wechseln Sie zu heißem Ausdruck
y_train_10 = to_categorical(y_train_10)
y_test_10 = to_categorical(y_test_10)
cifar10_resnet50.py
from keras.models import Model
from keras.layers import Input, Activation, Dense, GlobalAveragePooling2D, Conv2D
from keras import optimizers
from keras.layers.normalization import BatchNormalization as BN
from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping
#Referenz-URL: https://www.pynote.info/entry/keras-resnet-implementation
def shortcut_en(x, residual):
'''Erstellen Sie eine Verknüpfungsverbindung.
'''
x_shape = K.int_shape(x)
residual_shape = K.int_shape(residual)
if x_shape == residual_shape:
#Wenn x und Residuum dieselbe Form haben, tun Sie nichts.
shortcut = x
else:
#Wenn die Formen von x und Residuum unterschiedlich sind, führen Sie eine lineare Transformation durch, um sie an die Formen anzupassen.
stride_w = int(round(x_shape[1] / residual_shape[1]))
stride_h = int(round(x_shape[2] / residual_shape[2]))
shortcut = Conv2D(filters=residual_shape[3],
kernel_size=(1, 1),
strides=(stride_w, stride_h),
kernel_initializer='he_normal',
kernel_regularizer=l2(1.e-4))(x)
shortcut = BN()(shortcut)
return Add()([shortcut, residual])
def normal_resblock50(data, filters, strides=1):
x = Conv2D(filters=filters,kernel_size=(1,1),strides=(1,1),padding="same")(data)
x = BN()(x)
x = Activation("relu")(x)
x = Conv2D(filters=filters,kernel_size=(3,3),strides=(1,1),padding="same")(x)
x = BN()(x)
x = Activation("relu")(x)
x = Conv2D(filters=filters*4,kernel_size=(1,1),strides=strides,padding="same")(x)
x = BN()(x)
x = shortcut_en(data, x)
x = Activation("relu")(x)
return x
cifar10_resnet50.py
inputs = Input(shape = (32,32,3))
x = Conv2D(32,(5,5),padding = "SAME")(inputs)
x = BN()(x)
x = Activation('relu')(x)
x = normal_resblock50(x, 64, 1)
x = normal_resblock50(x, 64, 1)
x = normal_resblock50(x, 64, 1)
x = normal_resblock50(x, 128, 2)
x = normal_resblock50(x, 128, 1)
x = normal_resblock50(x, 128, 1)
x = normal_resblock50(x, 128, 1)
x = normal_resblock50(x, 256, 1)
x = normal_resblock50(x, 256, 1)
x = normal_resblock50(x, 256, 1)
x = normal_resblock50(x, 256, 1)
x = normal_resblock50(x, 256, 1)
x = normal_resblock50(x, 256, 1)
x = normal_resblock50(x, 512, 2)
x = normal_resblock50(x, 512, 1)
x = normal_resblock50(x, 512, 1)
x = GlobalAveragePooling2D()(x)
x = Dense(10)(x)
outputs = Activation("softmax")(x)
teacher_model = Model(inputs, outputs)
teacher_model.summary()
cifar10_resnet50.py
batch_size = 64
steps_per_epoch = y_train_10.shape[0] // batch_size
validation_steps = x_test_10.shape[0] // batch_size
log_dir = 'logs/softlabel/teacher/'
checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='val_loss', save_weights_only=True, save_best_only=True, period=1)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)
teacher_model.compile(loss = "categorical_crossentropy",optimizer = "adam", metrics = ["accuracy"])
trainj_gen = ImageDataGenerator(rescale = 1./255.).flow(x_train_10,y_train_10, batch_size)
val_gen = ImageDataGenerator(rescale = 1./255.).flow(x_test_10,y_test_10, batch_size)
cifar10_resnet50.py
history = teacher_model.fit_generator(train_gen,
initial_epoch=0,
epochs=250,
steps_per_epoch = steps_per_epoch,
validation_data = val_gen, validation_steps = validation_steps,
callbacks=[checkpoint])
history = teacher_model.fit_generator(trainj_gen,
initial_epoch=250,
epochs=300,
steps_per_epoch = steps_per_epoch,
validation_data = val_gen, validation_steps = validation_steps,
callbacks=[checkpoint, reduce_lr, early_stopping])
cifar10_resnet50.py
#Referenz-URL: https://qiita.com/yy1003/items/c590d1a26918e4abe512
def my_eval(model,x,t):
#model:Das Modell, das Sie bewerten möchten, x:Voraussichtliche Bildform= (batch,32,32,3) t:one-Hot Expression Label
ev = model.evaluate(x,t)
print("loss:" ,end = " ")
print(ev[0])
print("acc: ", end = "")
print(ev[1])
my_eval(teacher_model,x_test_10/255,y_test_10)
teacher_eval
10000/10000 [==============================] - 16s 2ms/step
loss: 0.817680492834933
acc: 0.883899986743927
Das Ergebnis war in den Testdaten zu 88,39% genau.
Bereiten Sie zunächst ein Bild zum Anbringen eines Pseudoetiketts vor. Obwohl es klein ist, habe ich für jede der 10 Klassen ungefähr 800 Blätter von imagenet gesammelt. Ich habe die Größe auf 32x32 geändert und daraus einen Datensatz gemacht.
Als detailliertes Verfahren
Es wird sein. Ich werde die Implementierung veröffentlichen, aber wenn Sie 3 und 4 befolgen, gibt es meiner Meinung nach keine feste Methode. Versuchen Sie daher, jede zu implementieren, damit dies einfach ist.
imagenet_dummy_label.py
img_path = r"D:\imagenet\cifar10\resize"
img_list = os.listdir(img_path)
x_train_imgnet = []
for i in img_list:
abs_path = os.path.join(img_path, i)
temp = load_img(abs_path)
temp = img_to_array(temp)
x_train_imgnet.append(temp)
x_train_imgnet = np.array(x_train_imgnet)
imagenet_dummy_label.py
#Stapelgrößeneinstellung
batch_size = 1
#Wie viele Schritte muss die Anweisung drehen?
step = int(x_train_imgnet.shape[0] / batch_size)
print(step)
#Leere Liste für Pseudo-Labels
y_train_imgnet_dummy = []
for i in range(step):
#Extrahieren Sie Bilddaten für die Stapelgröße
x_temp = x_train_imgnet[batch_size*i:batch_size*(i+1)]
#Normalisierung
x_temp = x_temp / 255.
#Inferenz
temp = teacher_model.predict(x_temp)
#Zur leeren Liste hinzufügen
y_train_imgnet_dummy.extend(temp)
#Liste zum numpy Array
y_train_imgnet_dummy = np.array(y_train_imgnet_dummy)
imagenet_dummy_label.py
#Schwellenwerteinstellung
threhold = 0.75
y_train_imgnet_dummy_th = y_train_imgnet_dummy[np.max(y_train_imgnet_dummy, axis=1) > threhold]
x_train_imgnet_th = x_train_imgnet[np.max(y_train_imgnet_dummy, axis=1) > threhold]
imagenet_dummy_label.py
#Index vom Onehot-Vektor zur Klassifizierung
y_student_all_dummy_label = np.argmax(y_train_imgnet_dummy_th, axis=1)
#Zählen Sie die Anzahl jeder Klasse von Pseudolabels
u, counts = np.unique(y_student_all_dummy_label, return_counts=True)
print(u, counts)
#Berechnen Sie die maximale Anzahl von Zählungen
student_label_max = max(counts)
#Trennen Sie das Numpy-Array für jedes Etikett
y_student_per_label = []
y_student_per_img_path = []
for i in range(10):
temp_l = y_train_imgnet_dummy_th[y_student_all_dummy_label == i]
print(i, ":", temp_l.shape)
y_student_per_label.append(temp_l)
temp_i = x_train_imgnet_th[y_student_all_dummy_label == i]
print(i, ":", temp_i.shape)
y_student_per_img_path.append(temp_i)
#Kopieren Sie die Daten für die maximale Anzahl auf jedem Etikett
y_student_per_label_add = []
y_student_per_img_add = []
for i in range(10):
num = y_student_per_label[i].shape[0]
temp_l = y_student_per_label[i]
temp_i = y_student_per_img_path[i]
add_num = student_label_max - num
q, mod = divmod(add_num, num)
print(q, mod)
temp_l_tile = np.tile(temp_l, (q+1, 1))
temp_i_tile = np.tile(temp_i, (q+1, 1, 1, 1))
temp_l_add = temp_l[:mod]
temp_i_add = temp_i[:mod]
y_student_per_label_add.append(np.concatenate([temp_l_tile, temp_l_add], axis=0))
y_student_per_img_add.append(np.concatenate([temp_i_tile, temp_i_add], axis=0))
#Überprüfen Sie die Zählnummer jedes Etiketts
print([len(i) for i in y_student_per_label_add])
#Kombinieren Sie Daten für jedes Etikett
student_train_img = np.concatenate(y_student_per_img_add, axis=0)
student_train_label = np.concatenate(y_student_per_label_add, axis=0)
#Kombiniert mit dem originalen cifar10 numpy Array
x_train_student = np.concatenate([x_train_10, student_train_img], axis=0)
y_train_student = np.concatenate([y_train_10, student_train_label], axis=0)
Hier werde ich mit resnet50 gehen, das die gleiche Größe wie das Lehrermodell hat. Als Modellgeräusch
Es gibt zwei. Für die Implementierung der stochastischen Tiefe habe ich auf die folgende Implementierung verwiesen, die auf github veröffentlicht wurde. Implementierungs-URL: https://github.com/transcranial/stochastic-depth/blob/master/stochastic-depth.ipynb
In meiner Implementierung Erstellen Sie zunächst eine Liste mit Wahrscheinlichkeiten für jeden Resblock. Wenn Sie das Modell definieren, nehmen Sie es einzeln heraus und verwenden Sie es. Ich mache es, weil ich dachte, es wäre besser, es zuerst zu definieren und später zu verwenden, damit es keine Fehler gibt.
stochastic_resblock.py
#Eine Funktion, die die Wahrscheinlichkeit definiert, mit der jeder Resblock angewendet wird
def get_p_survival(l, L, pl):
pt = 1 - (l / L) * (1 - pl)
return pt
#Ausgabe 1 oder 0 mit Wahrscheinlichkeit
#Während des Lernens: Ausgabe x 1 oder 0
#Zum Zeitpunkt der Inferenz: Ausgabe x Wahrscheinlichkeit
def stochastic_survival(y, p_survival=1.0):
# binomial random variable
survival = K.random_binomial((1,), p=p_survival)
# during testing phase:
# - scale y (see eq. (6))
# - p_survival effectively becomes 1 for all layers (no layer dropout)
return K.in_test_phase(tf.constant(p_survival, dtype='float32') * y,
survival * y)
def stochastic_resblock(data, filters, strides, depth_num, p_list):
print(p_list[depth_num])
x = Conv2D(filters=filters,kernel_size=(1,1),strides=(1,1),padding="same")(data)
x = BN()(x)
x = Activation("relu")(x)
x = Conv2D(filters=filters,kernel_size=(3,3),strides=(1,1),padding="same")(x)
x = BN()(x)
x = Activation("relu")(x)
x = Conv2D(filters=filters*4,kernel_size=(1,1),strides=strides,padding="same")(x)
x = BN()(x)
x = Lambda(stochastic_survival, arguments={'p_survival': p_list[depth_num]})(x)
x = shortcut_en(data, x)
x = Activation("relu")(x)
#Erhöhen Sie die Anzahl der Schichten
depth_num += 1
return x, depth_num
L = 16
pl = 0.8
p_list = []
for l in range(L+1):
x = get_p_survival(l,L,pl)
p_list.append(x)
#Beginnt bei 0, beginnt aber bei 1, um die Eingabeebene zu überspringen
depth_num = 1
inputs = Input(shape = (32,32,3))
x = Conv2D(32,(5,5),padding = "SAME")(inputs)
x = BN()(x)
x = Activation('relu')(x)
#depth_Verwenden Sie in der nächsten Ebene, während Sie num in der Funktion erhöhen
x, depth_num = stochastic_resblock(x, 64, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 64, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 64, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 128, 2, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 128, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 128, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 128, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 256, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 256, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 256, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 256, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 256, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 256, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 512, 2, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 512, 1, depth_num, p_list)
x, depth_num = stochastic_resblock(x, 512, 1, depth_num, p_list)
x = GlobalAveragePooling2D()(x)
x = Dropout(0.5)(x)
x = Dense(10)(x)
outputs = Activation("softmax")(x)
student_model = Model(inputs, outputs)
student_model.summary()
student_model.compile(loss = "categorical_crossentropy",optimizer = "adam", metrics = ["accuracy"])
Der Datensatz wurde in Schritt 2 erstellt, sodass nur noch Rand Augmentation übrig bleibt. Ich habe die folgende Implementierung verwendet, die auf github veröffentlicht wurde. Implementierungs-URL: https://github.com/heartInsert/randaugment/blob/master/Rand_Augment.py
Da das Datenformat der Github-Implementierung PIL ist, habe ich meinen eigenen Datengenerator erstellt, der Lehrerdaten ausgibt, während sie in ein Numpy-Array konvertiert werden.
Rand_Augment.py
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image, ImageEnhance, ImageOps
import numpy as np
import random
class Rand_Augment():
def __init__(self, Numbers=None, max_Magnitude=None):
self.transforms = ['autocontrast', 'equalize', 'rotate', 'solarize', 'color', 'posterize',
'contrast', 'brightness', 'sharpness', 'shearX', 'shearY', 'translateX', 'translateY']
if Numbers is None:
self.Numbers = len(self.transforms) // 2
else:
self.Numbers = Numbers
if max_Magnitude is None:
self.max_Magnitude = 10
else:
self.max_Magnitude = max_Magnitude
fillcolor = 128
self.ranges = {
# these Magnitude range , you must test it yourself , see what will happen after these operation ,
# it is no need to obey the value in autoaugment.py
"shearX": np.linspace(0, 0.3, 10),
"shearY": np.linspace(0, 0.3, 10),
"translateX": np.linspace(0, 0.2, 10),
"translateY": np.linspace(0, 0.2, 10),
"rotate": np.linspace(0, 360, 10),
"color": np.linspace(0.0, 0.9, 10),
"posterize": np.round(np.linspace(8, 4, 10), 0).astype(np.int),
"solarize": np.linspace(256, 231, 10),
"contrast": np.linspace(0.0, 0.5, 10),
"sharpness": np.linspace(0.0, 0.9, 10),
"brightness": np.linspace(0.0, 0.3, 10),
"autocontrast": [0] * 10,
"equalize": [0] * 10,
"invert": [0] * 10
}
self.func = {
"shearX": lambda img, magnitude: img.transform(
img.size, Image.AFFINE, (1, magnitude * random.choice([-1, 1]), 0, 0, 1, 0),
Image.BICUBIC, fill=fillcolor),
"shearY": lambda img, magnitude: img.transform(
img.size, Image.AFFINE, (1, 0, 0, magnitude * random.choice([-1, 1]), 1, 0),
Image.BICUBIC, fill=fillcolor),
"translateX": lambda img, magnitude: img.transform(
img.size, Image.AFFINE, (1, 0, magnitude * img.size[0] * random.choice([-1, 1]), 0, 1, 0),
fill=fillcolor),
"translateY": lambda img, magnitude: img.transform(
img.size, Image.AFFINE, (1, 0, 0, 0, 1, magnitude * img.size[1] * random.choice([-1, 1])),
fill=fillcolor),
"rotate": lambda img, magnitude: self.rotate_with_fill(img, magnitude),
# "rotate": lambda img, magnitude: img.rotate(magnitude * random.choice([-1, 1])),
"color": lambda img, magnitude: ImageEnhance.Color(img).enhance(1 + magnitude * random.choice([-1, 1])),
"posterize": lambda img, magnitude: ImageOps.posterize(img, magnitude),
"solarize": lambda img, magnitude: ImageOps.solarize(img, magnitude),
"contrast": lambda img, magnitude: ImageEnhance.Contrast(img).enhance(
1 + magnitude * random.choice([-1, 1])),
"sharpness": lambda img, magnitude: ImageEnhance.Sharpness(img).enhance(
1 + magnitude * random.choice([-1, 1])),
"brightness": lambda img, magnitude: ImageEnhance.Brightness(img).enhance(
1 + magnitude * random.choice([-1, 1])),
"autocontrast": lambda img, magnitude: ImageOps.autocontrast(img),
"equalize": lambda img, magnitude: img,
"invert": lambda img, magnitude: ImageOps.invert(img)
}
def rand_augment(self):
"""Generate a set of distortions.
Args:
N: Number of augmentation transformations to apply sequentially. N is len(transforms)/2 will be best
M: Max_Magnitude for all the transformations. should be <= self.max_Magnitude """
M = np.random.randint(0, self.max_Magnitude, self.Numbers)
sampled_ops = np.random.choice(self.transforms, self.Numbers)
return [(op, Magnitude) for (op, Magnitude) in zip(sampled_ops, M)]
def __call__(self, image):
operations = self.rand_augment()
for (op_name, M) in operations:
operation = self.func[op_name]
mag = self.ranges[op_name][M]
image = operation(image, mag)
return image
def rotate_with_fill(self, img, magnitude):
# I don't know why rotate must change to RGBA , it is copy from Autoaugment - pytorch
rot = img.convert("RGBA").rotate(magnitude)
return Image.composite(rot, Image.new("RGBA", rot.size, (128,) * 4), rot).convert(img.mode)
def test_single_operation(self, image, op_name, M=-1):
'''
:param image: image
:param op_name: operation name in self.transforms
:param M: -1 stands for the max Magnitude in there operation
:return:
'''
operation = self.func[op_name]
mag = self.ranges[op_name][M]
image = operation(image, mag)
return image
data_generator.py
img_augment = Rand_Augment(Numbers=2, max_Magnitude=10)
def get_random_data(x_train_i, y_train_i, data_aug):
x = array_to_img(x_train_i)
if data_aug:
seed_image = img_augment(x)
seed_image = img_to_array(seed_image)
else:
seed_image = x_train_i
seed_image = seed_image / 255
return seed_image, y_train_i
def data_generator(x_train, y_train, batch_size, data_aug):
'''data generator for fit_generator'''
n = len(x_train)
i = 0
while True:
image_data = []
label_data = []
for b in range(batch_size):
if i==0:
p = np.random.permutation(len(x_train))
x_train = x_train[p]
y_train = y_train[p]
image, label = get_random_data(x_train[i], y_train[i], data_aug)
image_data.append(image)
label_data.append(label)
i = (i+1) % n
image_data = np.array(image_data)
label_data = np.array(label_data)
yield image_data, label_data
Jetzt, wo wir einen Datengenerator haben, müssen wir nur noch lernen.
data_generator.py
log_dir = 'logs/softlabel/student1_2/'
checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='val_loss', save_weights_only=True, save_best_only=True, period=1)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)
batch_size = 64
steps_per_epoch = x_train_student.shape[0] // batch_size
validation_steps = x_test_10.shape[0] // batch_size
#Die Epoche 0-250 lernt, ohne die Lernrate zu ändern
history = student_model.fit_generator(data_generator(x_train_student, y_train_student, batch_size, data_aug = True),
initial_epoch=0,
epochs=250,
steps_per_epoch = steps_per_epoch,
validation_data = data_generator_wrapper(x_test_10, y_test_10, batch_size, data_aug = False),
validation_steps = validation_steps,
callbacks=[checkpoint])
#Unterbrechen Sie bei 250epoch-300epoch das Lernen, während Sie die Lernrate ändern
history = student_model.fit_generator(data_generator(x_train_student, y_train_student, batch_size, data_aug = True),
initial_epoch=250,
epochs=300,
steps_per_epoch = steps_per_epoch,
validation_data = data_generator_wrapper(x_test_10, y_test_10, batch_size, data_aug = False),
validation_steps = validation_steps,
callbacks=[checkpoint, reduce_lr, early_stopping])
eval.py
my_eval(student_model,x_test_10/255,y_test_10)
student_eval
10000/10000 [==============================] - 19s 2ms/step
loss: 0.24697399706840514
acc: 0.9394000172615051
Das Ergebnis war in den Testdaten zu 93,94% genau. Natürlich ist es vorbei.
Während ich dies tat, tauchte die Frage "Was ist genauer als wenn Rauschen zum Zeitpunkt des Lehrermodells aktiviert war" auf, also bestätigte ich es. Es ist in der folgenden Tabelle kurz zusammengefasst.
Experiment | Lehrer Modell- |
Datenverlust testen/accuracy | Schüler Modell- |
Datenverlust testen/accuracy |
---|---|---|---|---|
1 | LärmKeiner | 0.8176/88.39% | LärmJa | 0.2470/93.94% |
2 | LärmJa | 0.2492/94.14% | LärmJa | 0.2289/94.28% |
In diesem Fall war die Genauigkeit etwas höher, wenn der Lehrer Geräusche gab. Ich wollte unbedingt die Robustheit überprüfen, war aber erschöpft.
das ist alles. Wenn Sie Fragen oder Bedenken haben, hinterlassen Sie bitte einen Kommentar.