Deep Learning braucht Zeit, um nicht nur selbst zu lernen, sondern auch ein trainiertes Lernmodell zu betreiben. Ich möchte jedoch eine Objekterkennung in Echtzeit mit SSD (Single Shot MultiBox Detector) usw. durchführen! Wenn Sie ein Echtzeit-Action-Kampfspiel zwischen KI und Personen spielen möchten, die durch DQN (DeepQ Network) usw. gestärkt und erlernt wurden, wird die Echtzeit-Eigenschaft der Modellausführung sehr wichtig.
Kaufen Sie einen guten PC! Apropos, ich habe nicht so viel Geld und möchte es vielleicht portabel auf einem Notebook-PC ausführen. Daher werden wir dieses Mal überlegen, wie Keras (Tensor Flow) mit hoher Geschwindigkeit ausgeführt werden kann.
Machen wir das. Dieses Mal werde ich MNIST-Beispielanfänger und -experten als ein Beispiel ausprobieren, das so einfach wie möglich zu verstehen und zu versuchen ist. Platzieren Sie den diesmal erstellten Code auf github.
Es ist eine Geschichte ohne Körper oder Deckel, aber wenn Sie einen guten Grabber laden, AWS aufladen oder keine besonderen Einschränkungen in der Ausführungsumgebung haben können, stechen Sie TitanX und kaufen Sie jetzt einen speichergefüllten PC. Verschiedene Sites haben die CPU- und GPU-Geschwindigkeiten von TensorFlow verglichen. Beispiel: Dieser Artikel (Vergleich der Tensorflow-Ausführungsgeschwindigkeiten auf CPU / GPU / AWS In 5aa4a746b31b9be4838d)) gibt es einen zehnfachen Unterschied zwischen CPU und GPU.
Selbst wenn Sie in diesem Artikel Ihr Bestes geben, um die Geschwindigkeit zu erhöhen, ist er etwa zwei- bis fünfmal schneller als das Original. Wenn Sie diese Maßnahme also von Anfang an ergreifen können, ist dies definitiv besser. Ich bin in Schwierigkeiten, weil ich solche Maßnahmen nicht ergreifen kann! Ich mache es schon, aber ich möchte es schneller machen! Mal sehen, wie es weitergeht.
Schauen wir uns zunächst das MNIST-Beispiel für Anfänger an. Wenn Sie es implementieren, ohne in Keras nachzudenken,
#Modellieren
model = Sequential()
model.add(InputLayer(input_shape=input_shape, name='input'))
model.add(Dense(nb_classes))
model.add(Activation('softmax', name='softmax'))
optimizer = SGD(lr=0.5)
model.compile(loss='categorical_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
...
#Modelltraining
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,
verbose=1, validation_data=(X_test, Y_test))
...
#Modellbewertung
score = model.evaluate(X_test, Y_test, verbose=0)
...
#Modellausführung
model.predict(np.array([x])
Ich denke, es wird wie oben aussehen. Beachten Sie, dass sich die Methode zur sofortigen Ausführung des Modells mit Auswertung usw. von der Situation unterscheidet, in der neue Daten wie bei der Echtzeitausführung nacheinander eingehen, also diesmal
# X_Test ist 10000 1-Kanal 784-dimensionale Daten
start = time.perf_counter()
n_loop = 5
for n in range(n_loop):
predictions = [model.predict(np.array([x])) for x in X_test]
print('elapsed time for {} prediction {} [msec]'.format(len(X_test), (time.perf_counter()-start) * 1000 / n_loop))
Die Modellausführungsgeschwindigkeit wird gemessen, indem die Vorhersage 10000 Mal gedreht wird und die durchschnittlich verstrichene Zeit 5 Wochen lang genommen wird (um die Millisekundengenauigkeit zu messen, nicht "time.time ()", sondern "time". .pref_counter () `wird verwendet).
Das obige Ergebnis ist übrigens
elapsed time for 10000 prediction 3768.8394089927897 [msec]
war.
K.function
ausfrom keras import backend as K
pred = K.function([model.input], [model.output])
for n in range(n_loop):
predictions = [pred([np.array([x])]) for x in X_test]
Keras kann das Backend wie "aus dem Keras-Import-Backend" als K aufrufen, was auch in der offiziellen Dokumentation (https://keras.io/ja/backend/) erwähnt wird, aber "K. Sie können eine Instanz der Keras-Funktion mit function` erstellen. Wenn Sie das Modell von hier aus ausführen, können Sie die Ausführung etwas beschleunigen, anstatt Keras so wie es ist zu treffen. In diesem Fall
elapsed time for 10000 prediction 3210.0291186012328 [msec]
Es wurde wie.
Selbst wenn zwischen Keras und TensorFlow dasselbe Modell erstellt wird, gibt es zunächst einen erheblichen Unterschied in der Ausführungsgeschwindigkeit und der Lerngeschwindigkeit.
#Modellieren
x = tf.placeholder(tf.float32, [None, imageDim], name="input")
W = tf.Variable(tf.zeros([imageDim, outputDim]), dtype=tf.float32, name="Weight")
b = tf.Variable(tf.zeros([outputDim]), dtype=tf.float32, name="bias")
y = tf.nn.softmax(tf.matmul(x, W)+b, name="softmax")
#Objektive Funktionseinstellung
cross_entropy = tf.reduce_mean(
-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])
)
#Optimierungseinstellungen
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
#Modelltraining
sess.run(tf.global_variables_initializer())
for i in range(1000):
batch_xs, batch_ys = tfmnist.train.next_batch(100)
sess.run(train_step,feed_dict={x: batch_xs, y_: batch_ys})
#Modellbewertung
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
result = sess.run(
accuracy,
feed_dict={x: tfmnist.test.images, y_:tfmnist.test.labels}
)
#Modellausführung
sess.run(y, feed_dict={x: np.array([test_x])})
Es ist ein Vorteil von TensorFlow, dass Sie im Vergleich zu Keras detaillierte Einstellungen vornehmen können. Trotzdem ist der Teil des Schreibens des Modells unweigerlich kompliziert. Das Ergebnis der Ausführung des von TensorFlow erstellten Modells
elapsed time for 10000 prediction 2662.211540598946 [msec]
Es ist ersichtlich, dass die Geschwindigkeit im Vergleich zur Keras-Implementierung erheblich verbessert ist.
Es ist nicht so, dass Keras-Benutzer weinen und zu TensorFlow wechseln müssen. Sie können die Ausführungsgeschwindigkeit verbessern, indem Sie nur das Modell mit Keras erstellen und den Rest (Training, Vorhersage usw.) in TensorFlow ausführen.
import keras.backend.tensorflow_backend as KTF
import tensorflow as tf
old_session = KTF.get_session()
sess = tf.Session()
KTF.set_session(sess)
#Modellieren
model = Sequential()
model.add(InputLayer(input_shape=input_shape, name='input'))
model.add(Dense(nb_classes))
model.add(Activation('softmax', name='softmax'))
x = tf.placeholder(tf.float32, [None, imageDim], name="input")
y = model(x)
y_ = tf.placeholder(tf.float32, [None, nb_classes])
#Die Zielfunktion, die Erstellung des Optimierers und die Ausführung der Trainingsbewertung sind dieselben wie oben, daher werden sie weggelassen.
KTF.set_session(old_session)
Sie erhalten die Ausgabe y
, indem Sie den Eingabeplatzhalterx
erstellen und dem Modell zuweisen. Stellen Sie danach die Zielfunktion und den Optimierer gemäß der TensorFlow-Implementierungsmethode ein und drehen Sie das Training.
Mit dieser Methode wird das Ausführungsergebnis sein
elapsed time for 10000 prediction 2685.7926497992594 [msec]
Selbst wenn es sich bei dem Modellteil um eine Keras-Implementierung handelt, liegt die Ausführungsgeschwindigkeit sehr nahe an der TensorFlow-Implementierung.
Die Menge, die leicht durch Schlagen von Python erhöht werden kann, ist höchstens die oben genannte Stufe (sie kann schneller sein, wenn Sie PyPy usw. verwenden), und wenn Sie es schneller machen möchten, müssen Sie das Modell von C ++ ausführen. TensorFlow veröffentlicht TensorFlow Serving, eine API zur Verwendung trainierter Modelle in Anwendungen. Mit dieser API können Sie das Modell mit hoher Geschwindigkeit ausführen, indem Sie das TensorFlow-Modell auf der C ++ - Seite laden.
Wenn Sie ein Linux-Benutzer sind, können Sie es ohne Probleme ausführen, wenn Sie dem Tutorial folgen, aber es ist immer noch schwierig, es unter OSX auszuführen (ich konnte auch die Umgebung nicht erstellen, daher konnte ich diesmal die Details nicht schreiben ...), github Es gibt auch viele Probleme für OSX. Dieses Mal werde ich TensorFlow c ++ direkt ohne Serving drücken. Selbst wenn Serving verfügbar wird, ist es hilfreich, wenn Sie das Keras-Modell von C ++ aus aufrufen möchten.
Da Sie das TensorFlow-Verzeichnis direkt bedienen können, setzen Sie von einem einfach zu bedienenden Ort aus einen Link zum Tensorflow-Ordner unter pyenv usw. Wenn Sie das von pip installierte Verzeichnis nicht verschmutzen möchten, klonen Sie die entsprechende Version von github.
Führen Sie . / Configure
aus dem Stammverzeichnis des zu verwendenden Tensorflows aus. Sie werden aufgefordert, den zu verwendenden Compiler anzugeben und die Standardoptionen festzulegen. Grundsätzlich gibt es jedoch kein Problem mit der Standardspezifikation oder Ja. Wenn Sie jedoch keine GPU haben, beantworten Sie N auf die Frage, ob OpenCL oder CUDA aktiviert werden soll.
Zum Kompilieren von TensorFlow ist Bazel erforderlich, eine Open Source-Datei des Build-Tools, das ursprünglich von Google intern verwendet wurde. Die Installation wird unter Bezugnahme auf [hier] fortgesetzt (https://bazel.build/versions/master/docs/install.html). Mit OSX können Sie es auf einmal mit "Brew Install Bazel & Brew Upgrade Bazel" installieren.
Exportieren Sie Modelldaten in einer Form, die aus C ++ gelesen werden kann.
sess = tf.Session()
#Für Keras
import keras.backend.tensorflow_backend as KTF
KTF.set_session(sess)
...
saver = tf.train.Saver()
saver.save(sess, "models/" + "model.ckpt")
tf.train.write_graph(sess.graph.as_graph_def(), "models/", "graph.pb")
Für Modelle, die nicht trainiert werden müssen, können Gewichte festgelegt werden. Offizielle Dokumentation
What this does is load the GraphDef, pull in the values for all the variables from the latest checkpoint file, and then replace each Variable op with a Const that has the numerical data for the weights stored in its attributes It then strips away all the extraneous nodes that aren't used for forward inference, and saves out the resulting GraphDef into an output file.
Es scheint, dass die Größe der Modelldaten reduziert werden kann, indem die Parametervariable auf "Const" gesetzt und die Knoten gelöscht werden, die für die Ausführung nicht erforderlich sind (da die Parametervariable auf Const gesetzt ist, wird die Zugriffsgeschwindigkeit geringfügig verbessert? ).
Verwenden Sie freeze_graph.py
, um einzufrieren. Gehen Sie zum Stammverzeichnis von Tensorflow und
bazel build tensorflow/python/tools:freeze_graph && \
bazel-bin/tensorflow/python/tools/freeze_graph \
--input_graph=/path/to/graph.pb \
--input_checkpoint=/path/to/model.ckpt \
--output_graph=/path/to/output/frozen_graph.pb --output_node_names=softmax
Durch Drücken wird ein Diagramm generiert, das auf den durch "output_graph" angegebenen Pfad festgelegt ist (dies dauert lange, da beim ersten Mal verschiedene Kompilierungen ausgeführt werden). Wenn Sie nicht "output_node_names" angeben, werden Sie wütend, aber dies ist in TensorFlow.
y = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2)+b_fc2, name="softmax")
Sie können es einstellen, indem Sie ihm einen Namen wie geben. In Keras jedoch
model.add(Activation('softmax', name='softmax'))
Selbst wenn Sie als angeben, wird ein Fehler gedruckt, da er intern einen Alias hat. in diesem Fall
[print(n.name) for n in sess.graph.as_graph_def().node]
Bitte drucken Sie den Namen des Knotens direkt so aus und überprüfen Sie den intern festgelegten Namen (in Ihrer Umgebung war es Softmax).
Wir werden den CPP-Code schreiben, der das Modell liest und ausführt. Einzelheiten finden Sie unter Github, und ich werde die Hauptteile anhand eines Auszugs vorstellen. Erstellen Sie zunächst ein Verzeichnis für diese Zeit unter "tensorflow_ROOT / tensorflow" (diesmal Loadgraph) und erstellen Sie eine CC-Datei darin ("tensorflow_ROOT / tensorlow / loadgraph / mnist_tf.cc").
GraphDef graph_def;
status = ReadBinaryProto(Env::Default(), graph_file_name, &graph_def);
if (!status.ok()) {
cout << status.ToString() << "\n";
return 1;
}
cout << "loaded graph" << "\n";
// Add the graph to the session
status = session->Create(graph_def);
if (!status.ok()) {
cout << status.ToString() << "\n";
return 1;
}
Lesen Sie zuerst die Diagrammdaten und starten Sie die Sitzung.
Tensor x(DT_FLOAT, TensorShape({nTests, imageDim}));
MNIST mnist = MNIST("./MNIST_data/");
auto dst = x.flat<float>().data();
for (int i = 0; i < nTests; i++) {
auto img = mnist.testData.at(i).pixelData;
std::copy_n(img.begin(), imageDim, dst);
dst += imageDim;
}
const char* input_name = "input";
vector<pair<string, Tensor>> inputs = {
{input_name, x}
};
Erstellen Sie als Nächstes einen Eingangstensor "x" und füllen Sie ihn mit MNIST-Testdaten. Da 10000 768-dimensionale Float-Vektoren in mnist.testData gespeichert sind, werden sie einzeln in "x" registriert. Erstellen Sie dann ein Tensorpaar mit dem Namen, der auf der Python-Seite erstellt wurde. Dieser Name ist
# TensorFlow
x = tf.placeholder(tf.float32, [None, imageDim], name="input")
# Keras
InputLayer(input_shape=input_shape, name='input')
Es ist notwendig, die Entsprechung mit dem auf der Python-Seite angegebenen Namen wie zu nehmen. Erstellen Sie auf der Ausgabeseite auf die gleiche Weise einen Tensorvektor, registrieren Sie den Ausgabennamen (in diesem Fall Softmax), den Ausgabetensor und den zuvor in der Sitzung erstellten Eingabevektor und führen Sie ihn aus.
vector<Tensor> outputs;
// Run the session, evaluating our "softmax" operation from the graph
status = session->Run(inputs, {output_name}, {}, &outputs);
if (!status.ok()) {
cout << status.ToString() << "\n";
return 1;
}else{
cout << "Success run graph !! " << "\n";
}
Wenn das Modell erfolgreich ausgeführt wird, sollten die Ausgaben die Ausgabewerte enthalten.
int nHits = 0;
for (vector<Tensor>::iterator it = outputs.begin() ; it != outputs.end(); ++it) { //Ich drehe die Schleife, aber dieses Mal gibt es nur einen Ausgang, also Punkt= outputs.front()Synonym zu
auto items = it->shaped<float, 2>({nTests, 10}); //Klassifizierungsergebnis von 10 Zahlen 10 Dimensionen x 10000 Testdaten
for(int i = 0 ; i < nTests ; i++){
int arg_max = 0;
float val_max = items(i, 0);
for (int j = 0; j < 10; j++) {
if (items(i, j) > val_max) {
arg_max = j;
val_max = items(i, j);
}
} //Berechnen Sie den Index des Maximalwerts des 10-dimensionalen Vektors
if (arg_max == mnist.testData.at(i).label) {
nHits++;
}
}
}
float accuracy = (float)nHits/nTests;
Die Genauigkeit wird berechnet, indem die Lehrerdaten mit dem Ausführungsergebnis verglichen werden, wie in gezeigt.
Erstellen Sie abschließend eine BUILD-Datei (eine Datei, die Abhängigkeiten usw. beschreibt, z. B. eine make-Datei) in derselben Hierarchie wie die cpp-Datei.
cc_binary(
name = "mnistpredict_tf",
srcs = ["mnist_tf.cc", "MNIST.h"],
deps = [
"//tensorflow/core:tensorflow",
],
)
cc_binary(
name = "mnistpredict_keras",
srcs = ["mnist_keras.cc", "MNIST.h"],
deps = [
"//tensorflow/core:tensorflow",
],
)
Baue es.
bazel build -c opt --copt=-mavx --copt=-mavx2 --copt=-msse4.2 --copt=-msse4.1 --copt=-msse3 --copt=-mfma :mnistpredict_tf
bazel build -c opt --copt=-mavx --copt=-mavx2 --copt=-msse4.2 --copt=-msse4.1 --copt=-msse3 --copt=-mfma :mnistpredict_keras
Ich habe verschiedene Möglichkeiten, aber es ist nicht wesentlich.
The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.
The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
...
Ich war wütend auf verschiedene Dinge, also trage ich es diesmal.
Wenn die Kompilierung erfolgreich ist, wird eine ausführbare Datei mit dem Namen BUILD in "tensorflow_ROOT / bazel-bin / tensorflow / loadgraph" erstellt.
cd tensorflow_ROOT/bazel-bin/tensorflow/loadgraph
./mnistpredict_tf
Gehen Sie zu dieser Ebene, bringen Sie den Ordner MNIST_TEST und die festen Diagrammdaten und führen Sie sie aus (der Inhalt des Ordners MNIST_TEST muss erweitert werden).
Lassen Sie uns nun alle Ergebnisse der bisher eingeführten Muster zusammenfassen. Dies ist die Zeit (ms), die erforderlich ist, wenn der Vorhersageprozess des "Zurückgebens des Bestimmungsergebnisses, dessen Zahl zurückgegeben wird, wenn ein Stück 768-dimensionaler (28 × 28) Pixeldaten eingegeben wird" 1000 Mal (jeweils 5 Mal) wiederholt wird. Nimmt den Durchschnitt).
msec | Keras | Keras(K.function) | Keras(tf) | TensorFlow |
---|---|---|---|---|
Python | 3787 | 3242 | 2711 | 2588 |
C++ | 578 | - | 577 | 576 |
Erstens ist die Schleifenverarbeitungsleistung zwischen Python und C ++ überwältigend unterschiedlich, daher kann nicht geholfen werden, aber in einem einfachen Vergleich ist C ++ immer noch der überwältigende Sieg. Das Ergebnis ist, dass der einfache TensorFlow der schnellste unter den Python-Implementierungen ist, gefolgt vom Typ Keras-Ausführung tf. Die einfachen Keras sind erheblich langsamer als diese, aber Sie können eine leichte Geschwindigkeitsverbesserung feststellen, wenn Sie K.function ausführen.
Ich werde auch die Geschwindigkeit in der Experten-Edition vergleichen, die die Convolution-Ebene verwendet. Das Modell verwendet Folgendes.
Es ist fast das gleiche wie die Anfängerausgabe, daher werde ich es grob weglassen, aber es gibt einen Punkt, den Sie beachten sollten.
Es gibt kein Problem, wenn Sie Keras alleine verwenden, aber es gibt einen Grund, vorsichtig zu sein, wenn Sie K.function oder Keras und TensorFlow zusammen mit der Behandlung von learning_phase verwenden. Es ist erforderlich, das Flag "learning_phase" anzugeben, wenn sich das verwendete Modell zwischen Training und Test / Ausführung unterscheidet, z. B. wenn eine Dropout-Ebene vorhanden ist. Das Flag "learning_phase" gibt 1 während des Trainings und 0 während der Ausführung an.
Sie müssen K.learning_phase () für die Eingabe angeben und zur Laufzeit 0 eingeben.
# K.Bei Verwendung der Funktion
pred = K.function([model.input, K.learning_phase()], [model.output])
[pred([np.array([x]), 0]) for x in X_test]
#Bei Verwendung des Keras-Modells von TensorFlow
[sess.run(y, feed_dict={x: np.array([test_x]), K.learning_phase(): 0}) for test_x in X_test]
Ein Tensor vom Typ Bool wird erstellt, 0 wird zugewiesen und in der Eingabe mit dem Namen "keras_learning_phase" registriert.
Tensor lp(DT_BOOL, TensorShape({}));
lp.flat<bool>().setZero();
...
vector<pair<string, Tensor>> inputs = {
{input_name, x}, {"keras_learning_phase", lp}
};
Die Ergebnisse werden auf die gleiche Weise wie für Anfänger verglichen.
msec | Keras | Keras(K.function) | Keras(tf) | TensorFlow |
---|---|---|---|---|
Python | 9693 | 9087 | 8571 | 8124 |
C++ | 5528 | - | 5530 | 5512 |
Um ehrlich zu sein, dachte ich, dass es mehr Leistungsunterschiede zwischen Python und C ++ geben würde, aber es gab keinen großen Unterschied. Im Vergleich zur Python-Seite entspricht die Reihenfolge fast der der Anfänger-Edition.
Da es nicht direkt mit diesem Thema zusammenhängt, habe ich es als Bonus hinzugefügt, aber die Berechnungsgeschwindigkeit erhöht sich abhängig von der Auswahl von BLAS (Basic Linear Algebra Subprograms), das die Spezifikationen grundlegender Operationen in Bezug auf Matrizen und Vektoren definiert.
Informationen zur Verwendung von OpenBLAS finden Sie unter Ich habe zuvor einen Artikel geschrieben. Für Intel MKL
Linux: So installieren Sie mkl numpy OSX: Erstellen von mkl & numpy auf einem Mac
Sie haben uns sehr leicht verständliche Kommentarartikel gegeben, daher denke ich, dass Sie einen Blick darauf werfen sollten. Übrigens, wenn Sie Python aus Anaconda einfügen, werden standardmäßig Numpy und Scipy der MKL-Kompilierung eingeschlossen (diese Methode ist überwältigend einfach). Aber,[ Laut dem Artikel von Building mkl & numpy on mac ist es besser, es von MKL als über Anaconda zu übertragen. Es scheint teuer zu sein, daher kann ich nicht sagen, welches besser ist.
Informationen darüber, um wie viel sich die Berechnungsspezifikationen erhöhen, finden Sie in den oben genannten Artikeln und
Vergleich der SVD-Geschwindigkeiten für die Python-Singularitätszerlegung
Es gibt einen Artikel, der so verglichen wird. Ich denke, Sie sollten einen Blick darauf werfen, aber er scheint 20% bis mehrmals schneller zu sein (30% mehr in der Umgebung).
Es ist ein bisschen lange her, aber ich habe versucht zu sehen, wie stark sich die Ausführungsgeschwindigkeit mit Keras, TensorFlow und deren C ++ - Ausführung ändert. Infolgedessen ist TensorFlow am schnellsten, wenn Sie dies nur auf der Python-Seite tun und wenn es schwierig ist, ein Modell usw. zu erstellen, scheint der Hybridtyp, der Keras verwendet, gut zu sein. Wenn Sie C ++ verwenden, ändert sich die Geschwindigkeit nicht so stark, egal welche Sie verwenden. Sie ist daher schneller als die Python-Implementierung.
In der Expertenausgabe waren Python und C ++ fast 1,8-mal schneller, aber es gab keinen Unterschied als ich erwartet hatte. Ursprünglich sollte der Modellausführungsteil von TensorFlow eine Kompilierung von C ++ hinter sich haben, sodass der Unterschied, der diesmal auftrat, nicht der Unterschied in der Modellausführungsgeschwindigkeit war, sondern der Unterschied in der Schleifenverarbeitungsleistung usw. an anderen Stellen Ich glaube, es ist. Ich hatte also das Gefühl, dass es keinen großen Unterschied gibt, selbst wenn ich das Modell auf der Python-Seite drehe, außer wenn ich wirklich die Verarbeitungsgeschwindigkeit von C ++ in einem anderen Teil als der Modellausführung haben möchte, beispielsweise wenn ich es mit der Bildverarbeitungsumgebung kombiniere. Nächstes Mal werde ich es mit SSD versuchen.
Recommended Posts