|
| 1 | +using FluentAssertions; |
| 2 | +using Keras.Datasets; |
| 3 | +using Numpy; |
| 4 | +using NUnit.Framework; |
| 5 | + |
| 6 | +namespace MLTests |
| 7 | +{ |
| 8 | + public class NDLConvolutionDigitalRec |
| 9 | + { |
| 10 | + private NDarray _kernels; |
| 11 | + private NDarray _weights12; |
| 12 | + private string _dataPath; |
| 13 | + |
| 14 | + private static NDarray Tanh(NDarray layer) => np.tanh(layer); |
| 15 | + private static NDarray TanhToDerivative(NDarray layer) => 1 - np.power(layer, np.array(2)); |
| 16 | + private static NDarray Softmax(NDarray layer) |
| 17 | + { |
| 18 | + var temp = np.exp(layer); |
| 19 | + return temp / np.sum(temp, axis: 1, keepdims: true); |
| 20 | + } |
| 21 | + |
| 22 | + public NDarray GetImageSection(NDarray layer, int rowFrom, int rowTo, int colFrom, int colTo) |
| 23 | + { |
| 24 | + var subsection = layer[$":,{rowFrom}:{rowTo},{colFrom}{colTo}"]; |
| 25 | + return subsection.reshape(-1, 1, rowTo - rowFrom, colTo - colTo); |
| 26 | + } |
| 27 | + |
| 28 | + public NDLConvolutionDigitalRec(string dataPath) |
| 29 | + { |
| 30 | + _kernels = np.array(0f); |
| 31 | + _weights12 = np.array(0f); |
| 32 | + _dataPath = dataPath; |
| 33 | + } |
| 34 | + |
| 35 | + public void TrainOnMNISTDataWhithTath() |
| 36 | + { |
| 37 | + var ((x_train, y_train), (_, _)) = MNIST.LoadData(_dataPath); |
| 38 | + |
| 39 | + var (images, labels) = (x_train["0:1000"].reshape(1000, 28 * 28) / 255, y_train["0:1000"]); |
| 40 | + var one_hot_labels = np.zeros(labels.len, 10); |
| 41 | + for (var id = 0; id < labels.len; id++) |
| 42 | + { |
| 43 | + var label = labels[id]; |
| 44 | + one_hot_labels[id][label] = np.array(1); |
| 45 | + } |
| 46 | + labels = one_hot_labels; |
| 47 | + |
| 48 | + np.random.seed(1); |
| 49 | + |
| 50 | + var (alpha, iterations) = (2.0f, 30); |
| 51 | + var (pixels_per_image, num_labels) = (784, 10); |
| 52 | + var batch_size = 128; |
| 53 | + var input_rows = 28; |
| 54 | + var input_cols = 28; |
| 55 | + |
| 56 | + var kernel_rows = 3; |
| 57 | + var kernel_cols = 3; |
| 58 | + var num_kernels = 16; |
| 59 | + |
| 60 | + var hidden_size = (input_rows - kernel_rows) * (input_cols - kernel_cols) * num_kernels; |
| 61 | + |
| 62 | + _kernels = 0.02f * np.random.rand(kernel_rows * kernel_cols, num_kernels) - 0.01f; |
| 63 | + _weights12 = 0.2f * np.random.rand(hidden_size, num_labels) - 0.1f; |
| 64 | + |
| 65 | + for (var i = 0; i < iterations; i++) |
| 66 | + { |
| 67 | + var correct_cnt = 0; |
| 68 | + for (var imageId = 0; imageId < images.len / batch_size; ++imageId) |
| 69 | + { |
| 70 | + var (batch_start, batch_end) = (imageId * batch_size, (imageId + 1) * batch_size); |
| 71 | + var layer_0 = images[$"{batch_start}:{batch_end}"]; |
| 72 | + layer_0 = layer_0.reshape(layer_0.shape[0], 28, 28); |
| 73 | + var shape = layer_0.shape; |
| 74 | + |
| 75 | + var layer_1 = Tanh(np.dot(layer_0, _kernels)); |
| 76 | + var dropout_mask = np.random.randint(2, null, layer_1.shape.Dimensions); |
| 77 | + layer_1 *= dropout_mask * 2; |
| 78 | + var layer_2 = Softmax(np.dot(layer_1, _weights12)); |
| 79 | + |
| 80 | + var layer_2_delta = (labels[$"{batch_start}:{batch_end}"] - layer_2) / (batch_size * layer_2.shape[0]); |
| 81 | + var layer_1_delta = layer_2_delta.dot(_weights12.T) * TanhToDerivative(layer_1); |
| 82 | + layer_1_delta *= dropout_mask; |
| 83 | + |
| 84 | + |
| 85 | + _weights12 += alpha * layer_1.T.dot(layer_2_delta); |
| 86 | + _kernels += alpha * layer_0.T.dot(layer_1_delta); |
| 87 | + } |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + public int PredictNumber(int testId) |
| 92 | + { |
| 93 | + var ((x_train, y_train), (x_test, y_test)) = MNIST.LoadData(_dataPath); |
| 94 | + |
| 95 | + var test_images = x_test.reshape(x_test.len, 28 * 28) / 255; |
| 96 | + var test_labels = np.zeros(y_test.len, 10); |
| 97 | + for (var id = 0; id < y_test.len; id++) |
| 98 | + { |
| 99 | + var test = y_test[id]; |
| 100 | + test_labels[id][test] = np.array(1); |
| 101 | + } |
| 102 | + |
| 103 | + var layer_0 = test_images[$"{testId}:{testId + 1}"]; |
| 104 | + var layer_1 = Tanh(np.dot(layer_0, _kernels)); |
| 105 | + var layer_2 = np.dot(layer_1, _weights12); |
| 106 | + var result = layer_2.GetData<double>(); |
| 107 | + var max = result.Max(); |
| 108 | + return result.Select((e, index) => new { e, index }).OrderBy(e => e.e).Last().index; |
| 109 | + } |
| 110 | + |
| 111 | + } |
| 112 | + |
| 113 | + public class NDLConvolutionDigitalRecTest |
| 114 | + { |
| 115 | + [Test] |
| 116 | + public void ShouldPredictByUsingTathActivationFunc() |
| 117 | + { |
| 118 | + var recognizer = new NDLConvolutionDigitalRec(Path.GetFullPath(@"D:/projects.active/LearnML/data/mnist.npz")); |
| 119 | + recognizer.TrainOnMNISTDataWhithTath(); |
| 120 | + var result = recognizer.PredictNumber(0); |
| 121 | + result.Should().Be(7); |
| 122 | + } |
| 123 | + } |
| 124 | +} |
0 commit comments