mnist-cnn.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/env python3
  2. import sys
  3. import gguf
  4. import numpy as np
  5. from tensorflow import keras
  6. from tensorflow.keras import layers
  7. def train(model_name):
  8. # Model / data parameters
  9. num_classes = 10
  10. input_shape = (28, 28, 1)
  11. # Load the data and split it between train and test sets
  12. (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
  13. # Scale images to the [0, 1] range
  14. x_train = x_train.astype("float32") / 255
  15. x_test = x_test.astype("float32") / 255
  16. # Make sure images have shape (28, 28, 1)
  17. x_train = np.expand_dims(x_train, -1)
  18. x_test = np.expand_dims(x_test, -1)
  19. print("x_train shape:", x_train.shape)
  20. print(x_train.shape[0], "train samples")
  21. print(x_test.shape[0], "test samples")
  22. # convert class vectors to binary class matrices
  23. y_train = keras.utils.to_categorical(y_train, num_classes)
  24. y_test = keras.utils.to_categorical(y_test, num_classes)
  25. model = keras.Sequential(
  26. [
  27. keras.Input(shape=input_shape),
  28. layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
  29. layers.MaxPooling2D(pool_size=(2, 2)),
  30. layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
  31. layers.MaxPooling2D(pool_size=(2, 2)),
  32. layers.Flatten(),
  33. layers.Dropout(0.5),
  34. layers.Dense(num_classes, activation="softmax"),
  35. ]
  36. )
  37. model.summary()
  38. batch_size = 128
  39. epochs = 15
  40. model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
  41. model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)
  42. score = model.evaluate(x_test, y_test, verbose=0)
  43. print("Test loss:", score[0])
  44. print("Test accuracy:", score[1])
  45. model.save(model_name)
  46. print("Keras model saved to '" + model_name + "'")
  47. def convert(model_name):
  48. model = keras.models.load_model(model_name)
  49. gguf_model_name = model_name + ".gguf"
  50. gguf_writer = gguf.GGUFWriter(gguf_model_name, "mnist-cnn")
  51. kernel1 = model.layers[0].weights[0].numpy()
  52. kernel1 = np.moveaxis(kernel1, [2,3], [0,1])
  53. kernel1 = kernel1.astype(np.float16)
  54. gguf_writer.add_tensor("kernel1", kernel1, raw_shape=(32, 1, 3, 3))
  55. bias1 = model.layers[0].weights[1].numpy()
  56. bias1 = np.repeat(bias1, 26*26)
  57. gguf_writer.add_tensor("bias1", bias1, raw_shape=(1, 32, 26, 26))
  58. kernel2 = model.layers[2].weights[0].numpy()
  59. kernel2 = np.moveaxis(kernel2, [0,1,2,3], [2,3,1,0])
  60. kernel2 = kernel2.astype(np.float16)
  61. gguf_writer.add_tensor("kernel2", kernel2, raw_shape=(64, 32, 3, 3))
  62. bias2 = model.layers[2].weights[1].numpy()
  63. bias2 = np.repeat(bias2, 11*11)
  64. gguf_writer.add_tensor("bias2", bias2, raw_shape=(1, 64, 11, 11))
  65. dense_w = model.layers[-1].weights[0].numpy()
  66. dense_w = dense_w.transpose()
  67. gguf_writer.add_tensor("dense_w", dense_w, raw_shape=(10, 1600))
  68. dense_b = model.layers[-1].weights[1].numpy()
  69. gguf_writer.add_tensor("dense_b", dense_b)
  70. gguf_writer.write_header_to_file()
  71. gguf_writer.write_kv_data_to_file()
  72. gguf_writer.write_tensors_to_file()
  73. gguf_writer.close()
  74. print("Model converted and saved to '{}'".format(gguf_model_name))
  75. if __name__ == '__main__':
  76. if len(sys.argv) < 3:
  77. print("Usage: %s <train|convert> <model_name>".format(sys.argv[0]))
  78. sys.exit(1)
  79. if sys.argv[1] == 'train':
  80. train(sys.argv[2])
  81. elif sys.argv[1] == 'convert':
  82. convert(sys.argv[2])
  83. else:
  84. print("Usage: %s <train|convert> <model_name>".format(sys.argv[0]))
  85. sys.exit(1)