diff --git a/labworks/LW1/IS_lab_4.png b/labworks/LW1/IS_lab_4.png new file mode 100644 index 0000000..9ce5f26 Binary files /dev/null and b/labworks/LW1/IS_lab_4.png differ diff --git a/labworks/LW1/IS_lab_4_90.png b/labworks/LW1/IS_lab_4_90.png new file mode 100644 index 0000000..c520ac8 Binary files /dev/null and b/labworks/LW1/IS_lab_4_90.png differ diff --git a/labworks/LW1/IS_lab_7.png b/labworks/LW1/IS_lab_7.png new file mode 100644 index 0000000..6479bad Binary files /dev/null and b/labworks/LW1/IS_lab_7.png differ diff --git a/labworks/LW1/IS_lab_7_90.png b/labworks/LW1/IS_lab_7_90.png new file mode 100644 index 0000000..74df118 Binary files /dev/null and b/labworks/LW1/IS_lab_7_90.png differ diff --git a/labworks/LW1/best_model_100.keras b/labworks/LW1/best_model_100.keras new file mode 100644 index 0000000..6eb2bba Binary files /dev/null and b/labworks/LW1/best_model_100.keras differ diff --git a/labworks/LW1/images_for_report/1.png b/labworks/LW1/images_for_report/1.png new file mode 100644 index 0000000..363b58f Binary files /dev/null and b/labworks/LW1/images_for_report/1.png differ diff --git a/labworks/LW1/images_for_report/10.png b/labworks/LW1/images_for_report/10.png new file mode 100644 index 0000000..c873a7f Binary files /dev/null and b/labworks/LW1/images_for_report/10.png differ diff --git a/labworks/LW1/images_for_report/11.png b/labworks/LW1/images_for_report/11.png new file mode 100644 index 0000000..b4fa3dd Binary files /dev/null and b/labworks/LW1/images_for_report/11.png differ diff --git a/labworks/LW1/images_for_report/12.png b/labworks/LW1/images_for_report/12.png new file mode 100644 index 0000000..b2a8586 Binary files /dev/null and b/labworks/LW1/images_for_report/12.png differ diff --git a/labworks/LW1/images_for_report/13.png b/labworks/LW1/images_for_report/13.png new file mode 100644 index 0000000..2280e6a Binary files /dev/null and b/labworks/LW1/images_for_report/13.png differ diff --git a/labworks/LW1/images_for_report/14.png b/labworks/LW1/images_for_report/14.png new file mode 100644 index 0000000..30c0f9b Binary files /dev/null and b/labworks/LW1/images_for_report/14.png differ diff --git a/labworks/LW1/images_for_report/15.png b/labworks/LW1/images_for_report/15.png new file mode 100644 index 0000000..ab1900c Binary files /dev/null and b/labworks/LW1/images_for_report/15.png differ diff --git a/labworks/LW1/images_for_report/16.png b/labworks/LW1/images_for_report/16.png new file mode 100644 index 0000000..bd7b4d0 Binary files /dev/null and b/labworks/LW1/images_for_report/16.png differ diff --git a/labworks/LW1/images_for_report/17.png b/labworks/LW1/images_for_report/17.png new file mode 100644 index 0000000..b045500 Binary files /dev/null and b/labworks/LW1/images_for_report/17.png differ diff --git a/labworks/LW1/images_for_report/18.png b/labworks/LW1/images_for_report/18.png new file mode 100644 index 0000000..b0d8000 Binary files /dev/null and b/labworks/LW1/images_for_report/18.png differ diff --git a/labworks/LW1/images_for_report/19.png b/labworks/LW1/images_for_report/19.png new file mode 100644 index 0000000..e586cdd Binary files /dev/null and b/labworks/LW1/images_for_report/19.png differ diff --git a/labworks/LW1/images_for_report/2.png b/labworks/LW1/images_for_report/2.png new file mode 100644 index 0000000..1c52d9d Binary files /dev/null and b/labworks/LW1/images_for_report/2.png differ diff --git a/labworks/LW1/images_for_report/3.png b/labworks/LW1/images_for_report/3.png new file mode 100644 index 0000000..242c9dd Binary files /dev/null and b/labworks/LW1/images_for_report/3.png differ diff --git a/labworks/LW1/images_for_report/4.png b/labworks/LW1/images_for_report/4.png new file mode 100644 index 0000000..7441a05 Binary files /dev/null and b/labworks/LW1/images_for_report/4.png differ diff --git a/labworks/LW1/images_for_report/5.png b/labworks/LW1/images_for_report/5.png new file mode 100644 index 0000000..3aefd63 Binary files /dev/null and b/labworks/LW1/images_for_report/5.png differ diff --git a/labworks/LW1/images_for_report/6.png b/labworks/LW1/images_for_report/6.png new file mode 100644 index 0000000..34dc189 Binary files /dev/null and b/labworks/LW1/images_for_report/6.png differ diff --git a/labworks/LW1/images_for_report/7.png b/labworks/LW1/images_for_report/7.png new file mode 100644 index 0000000..8f475e8 Binary files /dev/null and b/labworks/LW1/images_for_report/7.png differ diff --git a/labworks/LW1/images_for_report/8.png b/labworks/LW1/images_for_report/8.png new file mode 100644 index 0000000..80d3248 Binary files /dev/null and b/labworks/LW1/images_for_report/8.png differ diff --git a/labworks/LW1/images_for_report/9.png b/labworks/LW1/images_for_report/9.png new file mode 100644 index 0000000..4103aa6 Binary files /dev/null and b/labworks/LW1/images_for_report/9.png differ diff --git a/labworks/LW1/report.md b/labworks/LW1/report.md new file mode 100644 index 0000000..0f755c2 --- /dev/null +++ b/labworks/LW1/report.md @@ -0,0 +1,508 @@ +# Отчёт по лабораторной работе №1 + +**Кобзев Александр, Кирсанов Егор — А-01-22** + +## 1. В среде Google Colab создан новый блокнот. Импортированы необходимые библиотеки и модули. + +```python +from google.colab import drive +drive.mount('/content/drive') +``` + +```python +from tensorflow import keras +import matplotlib.pyplot as plt +import numpy as np +import sklearn +from keras.datasets import mnist +from sklearn.model_selection import train_test_split +from tensorflow.keras.utils import to_categorical +from keras.models import Sequential +from keras.layers import Dense +from PIL import Image +``` + + +--- + +## 2. Загрузили набора данных MNIST с изображениями рукописных цифр. + +```python +(X_train, y_train), (X_test, y_test) = mnist.load_data() +``` + +--- + +## 3. Разбили данные на обучающую и тестовую выборки 60 000:10 000. + +При объединении исходных выборок и последующем разбиении был использован параметр `random_state = 4*k - 1`, где *k* – номер бригады (k = 10). Такой фиксированный seed обеспечивает воспроизводимость разбиения. + +```python +# объединяем исходные обучающие и тестовые данные в один массив +X = np.concatenate((X_train, X_test)) +y = np.concatenate((y_train, y_test)) + +# выполняем разбиение на обучающую (60000) и тестовую (10000) выборки +X_train, X_test, y_train, y_test = train_test_split( + X, y, train_size=60000, test_size=10000, random_state=4*10 - 1 +) + +# вывод размерностей полученных массивов +print('Shape of X train:', X_train.shape) +print('Shape of y test:', y_test.shape) +``` + +``` +Shape of X train: (60000, 28, 28) +Shape of y train: (60000,) +``` + +--- + +## 4. Вывели первые 4 элемента обучающих данных (изображения и метки цифр). + +```python +# вывод изображения +fig, axes = plt.subplots(1, 4, figsize=(10, 3)) +for i in range(4): + axes[i].imshow(X_train[i], cmap=plt.get_cmap('gray')) + axes[i].set_title(y_train[i]) + axes[i].axis('off') +plt.show() +``` +![Примеры изображений](images_for_report/1.png) + +--- + +## 5. Провели предобработку данных: привели обучающие и тестовые данные к формату, пригодному для обучения нейронной сети. Входные данные должны принимать значения от 0 до 1, метки цифр должны быть закодированы по принципу «one-hot encoding». Вывели размерности предобработанных обучающих и тестовых массивов данных. + +```python +# развернем каждое изображение 28*28 в вектор 784 +num_pixels = X_train.shape[1] * X_train.shape[2] +X_train = X_train.reshape(X_train.shape[0], num_pixels) / 255.0 +X_test = X_test.reshape(X_test.shape[0], num_pixels) / 255.0 +print('Shape of transformed X train:', X_train.shape) +``` + +``` +Shape of transformed X train: (60000, 784) +``` + +```python +# переведем метки в one-hot +from tensorflow.keras.utils import to_categorical +y_train = to_categorical(y_train) +y_test = to_categorical(y_test) +``` + +``` +Shape of transformed y train: (60000, 10) +``` + +--- + +## 6. Реализовали и обученили однослойную нейронную сеть. + +**Архитектура и параметры:** +- количество скрытых слоёв: 0 +- функция активации выходного слоя: `softmax` +- функция ошибки: `categorical_crossentropy` +- алгоритм обучения: `sgd` +- метрика качества: `accuracy` +- количество эпох: 50 +- доля валидационных данных от обучающих: 0.1 + +```python +model = Sequential() +model.add(Dense(units=10, input_dim=num_pixels, activation='softmax')) +model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) +model.summary() +``` + +![архитектура модели](images_for_report/2.png) + +```python +#обучение +H1 = model.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150) +``` + +```python +# вывод графика ошибки по эпохам +plt.plot(H1.history['loss']) +plt.plot(H1.history['val_loss']) +plt.grid() +plt.xlabel('Epochs') +plt.ylabel('loss') +plt.legend(['train_loss', 'val_loss']) +plt.title('Loss by epochs') +plt.show() +``` + +![граффик обучения](images_for_report/3.png) +--- + +## 7. Применили обученную модель к тестовым данным. + +```python +# Оценка качества работы модели на тестовых данных +scores = model.evaluate(X_test, y_test) +print('Loss on test data:', scores[0]) +print('Accuracy on test data:', scores[1]) +``` + +``` +Loss on test data: 0.32417795062065125 +Accuracy on test data: 0.9110999703407288 +``` + +## 8. Добавили в модель один скрытый слой и провели обучение и тестирование (повторить п. 6–7) при 100, 300, 500 нейронах в скрытом слое. По метрике качества классификации на тестовых данных выбрали наилучшее количество нейронов в скрытом слое. В качестве функции активации нейронов в скрытом слое использовали функцию sigmoid. + +### При 100 нейронах: +```python +model_100 = Sequential () +model_100.add(Dense(units=100,input_dim=num_pixels, activation='sigmoid')) +model_100.add(Dense(units=num_classes, activation='softmax')) +model_100.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) +print(model_100.summary()) +``` + +![архитектура модели](images_for_report/4.png) + +```python +#обучение +H_100 = model_100.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150) +``` + +```python +# вывод графика ошибки по эпохам +plt.plot(H_100.history['loss']) +plt.plot(H_100.history['val_loss']) +plt.grid() +plt.xlabel('Epochs') +plt.ylabel('loss') +plt.legend(['train_loss', 'val_loss']) +plt.title('Loss by epochs') +plt.show() +``` + +![граффик обучения](images_for_report/5.png) + +```python +# Оценка качества работы модели на тестовых данных +scores = model_100.evaluate(X_test, y_test) +print('Loss on test data:', scores[0]) +print('Accuracy on test data:', scores[1]) +``` + +``` +Loss on test data: 0.2998492121696472 +Accuracy on test data: 0.9138000011444092 +``` + +### При 300 нейронах: +```python +model_300 = Sequential () +model_300.add(Dense(units=300,input_dim=num_pixels, activation='sigmoid')) +model_300.add(Dense(units=num_classes, activation='softmax')) +model_300.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) +print(model_300.summary()) +``` + +![архитектура модели](images_for_report/6.png) + +```python +H_300 = model_300.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150) +``` + +```python +# вывод графика ошибки по эпохам +plt.plot(H_300.history['loss']) +plt.plot(H_300.history['val_loss']) +plt.grid() +plt.xlabel('Epochs') +plt.ylabel('loss') +plt.legend(['train_loss', 'val_loss']) +plt.title('Loss by epochs') +plt.show() +``` + +![граффик обучения](images_for_report/7.png) + +```python +# Оценка качества работы модели на тестовых данных +scores = model_300.evaluate(X_test, y_test) +print('Loss on test data:', scores[0]) +print('Accuracy on test data:', scores[1]) +``` + +``` +Loss on test data: 0.31299835443496704 +Accuracy on test data: 0.9107999801635742 +``` + +### При 500 нейронах: +```python +model_500 = Sequential() +model_500.add(Dense(units=500, input_dim=num_pixels, activation='sigmoid')) +model_500.add(Dense(units=num_classes, activation='softmax')) +model_500.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) +print(model_500.summary()) +``` + +![архитектура модели](images_for_report/8.png) + + +```python +H_500 = model_500.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150) +``` + +```python +# вывод графика ошибки по эпохам +plt.plot(H_500.history['loss']) +plt.plot(H_500.history['val_loss']) +plt.grid() +plt.xlabel('Epochs') +plt.ylabel('loss') +plt.legend(['train_loss', 'val_loss']) +plt.title('Loss by epochs') +plt.show() +``` + +![граффик обучения](images_for_report/9.png) + +```python +# Оценка качества работы модели на тестовых данных +scores = model_500.evaluate(X_test, y_test) +print('Loss on test data:', scores[0]) +print('Accuracy on test data:', scores[1]) +``` + +``` +Loss on test data: 0.31795090436935425 +Accuracy on test data: 0.909600019454956 +``` + +Мы видим что лучший результат показала модель со 100 нейронами в скрытом слое(Accuracy = 0.9138). + +## 9. Добавили в наилучшую архитектуру, определенную в п. 8, второй скрытый слой и провели обучение и тестирование при 50 и 100 нейронах во втором скрытом слое. В качестве функции активации нейронов в скрытом слое использовали функцию sigmoid. + +### При 50 нейронах в 2-м слое: +```python +model_100_50 = Sequential() +model_100_50.add(Dense(units=100, input_dim=num_pixels, activation='sigmoid')) +model_100_50.add(Dense(units=50, activation='sigmoid')) +model_100_50.add(Dense(units=num_classes, activation='softmax')) +model_100_50.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) +print(model_100_50.summary()) +``` + +![архитектура модели](images_for_report/10.png) + +```python +H_100_50 = model_100_50.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150) +``` + +```python +# вывод графика ошибки по эпохам +plt.plot(H_100_50.history['loss']) +plt.plot(H_100_50.history['val_loss']) +plt.grid() +plt.xlabel('Epochs') +plt.ylabel('loss') +plt.legend(['train_loss', 'val_loss']) +plt.title('Loss by epochs') +plt.show() +``` + +![граффик обучения](images_for_report/11.png) + +```python +# Оценка качества работы модели на тестовых данных +scores = model_100_50.evaluate(X_test, y_test) +print('Loss on test data:', scores[0]) +print('Accuracy on test data:', scores[1]) +``` + +``` +Loss on test data: 0.3216394782066345 +Accuracy on test data: 0.9085999727249146 +``` + +### При 100 нейронах во 2-м слое:\ + +```python +model_100_100 = Sequential() +model_100_100.add(Dense(units=100, input_dim=num_pixels, activation='sigmoid')) +model_100_100.add(Dense(units=100, activation='sigmoid')) +model_100_100.add(Dense(units=num_classes, activation='softmax')) +model_100_100.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy']) +print(model_100_100.summary()) +``` + +![архитектура модели](images_for_report/12.png) + +```python +H_100_100 = model_100_100.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150) +``` + +```python +# вывод графика ошибки по эпохам +plt.plot(H_100_100.history['loss']) +plt.plot(H_100_100.history['val_loss']) +plt.grid() +plt.xlabel('Epochs') +plt.ylabel('loss') +plt.legend(['train_loss', 'val_loss']) +plt.title('Loss by epochs') +plt.show() +``` + +![граффик обучения](images_for_report/13.png) + +```python +# Оценка качества работы модели на тестовых данных +scores = model.evaluate(X_test, y_test) +print('Loss on test data:', scores[0]) +print('Accuracy on test data:', scores[1]) +``` + +``` +Loss on test data: 0.31788304448127747 +Accuracy on test data: 0.9128000140190125 +``` + +## 10. Сравнили качество классификации на тестовых данных всех построенных моделей. Сделали выводы. + +| Кол-во слоёв | Нейронов в 1-м | Нейронов во 2-м | Accuracy | +|---------------|----------------|-----------------|-----------| +| 0 | – | – | 0.9111 | +| 1 | 100 | – | 0.9138 | +| 1 | 300 | – | 0.9108 | +| 1 | 500 | – | 0.9096 | +| 2 | 100 | 50 | 0.9086 | +| 2 | 100 | 100 | 0.9128 | + +**Вывод:** наилучшей оказалась архитектура с одним скрытым слоем и 100 нейронами в нём. Увеличение числа нейронов в скрытом слое или добавление второго слоя не улучшило качество классификации, а в некоторых случаях даже ухудшило его. Вероятно, это связано с переобучением модели из-за избыточного количества параметров при относительно небольшом объёме обучающих данных. + +--- + +## 11. Сохранили наилучшую модель на диск. + +```python +model_100.save("/content/drive/MyDrive/Colab Notebooks/best_model_100.keras") +``` + +--- + +## 12. Для нейронной сети с наилучшей архитектурой вывели 2 тестовых изображения и истинные метки, а также предсказанные моделью метки. + +```python +n = 333 +result = model_100.predict(X_test[n:n+1]) +print('NNoutput:',result) +plt.imshow(X_test[n].reshape(28,28),cmap=plt.get_cmap('gray')) +plt.show() +print('Realmark:',str(np.argmax(y_test[n]))) +print('NNanswer:',str(np.argmax(result))) +``` +![Пример 1](images_for_report/14.png) + +```python +n = 234 +result = model_100.predict(X_test[n:n+1]) +print('NNoutput:',result) +plt.imshow(X_test[n].reshape(28,28),cmap=plt.get_cmap('gray')) +plt.show() +print('Realmark:',str(np.argmax(y_test[n]))) +print('NNanswer:',str(np.argmax(result))) +``` +![Пример 2](images_for_report/15.png) + +--- + +## 13. Создали собственные изображения рукописных цифр, подобное представленным в наборе MNIST. Цифру выбрали как остаток от деления на 10 числа своего дня рождения (14 июля → 14 mod 10 = 4, 7 ноября → 7 mod 10 = 7). Сохранили изображения. Загрузили, предобработали и подали на вход обученной нейронной сети собственные изображения. Вывели изображения и результаты распознавания. + +### Для 7: + +![Изображение "7"](IS_lab_7.png) + +```python +#вывод собственного изображения +plt.imshow(test_img,cmap=plt.get_cmap('gray')) +plt.show() +#предобработка +test_img=test_img/255 +test_img=test_img.reshape(1,num_pixels) +#распознавание +result=model_100.predict(test_img) +print('I think it\'s',np.argmax(result)) +``` +![Отображение "7"](images_for_report/16.png) + +### Для 4: + +![Мое изображение "4"](IS_lab_4.png) + +```python +from PIL import Image +file_data_4=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_4.png') +file_data_4=file_data_4.convert('L') +test_img_4=np.array(file_data_4) +#вывод собственного изображения +plt.imshow(test_img_4,cmap=plt.get_cmap('gray')) +plt.show() +#предобработка +test_img_4=test_img_4/255 +test_img_4=test_img_4.reshape(1,num_pixels) +#распознавание +result=model_100.predict(test_img_4) +print('I think it\'s',np.argmax(result)) +``` +![Отображение "4"](images_for_report/17.png) + +--- + +## 14. Создать копию собственного изображения, отличающуюся от оригинала поворотом на 90 градусов в любую сторону. Сохранили изображения. Загрузили, предобработали и подали на вход обученной нейронной сети измененные изображения. Вывели изображения и результаты распознавания. Сделали выводы по результатам эксперимента. + +```python +from PIL import Image +file_data=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_7_90.png') +file_data=file_data.convert('L') +test_img=np.array(file_data) +#вывод собственного изображения +plt.imshow(test_img,cmap=plt.get_cmap('gray')) +plt.show() +#предобработка +test_img=test_img/255 +test_img=test_img.reshape(1,num_pixels) +#распознавание +result=model_100.predict(test_img) +print('Ithinkit\'s',np.argmax(result)) +``` + +![Отображение "7 повернутой"](images_for_report/18.png) + +```python +from PIL import Image +file_data_4=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_4_90.png') +file_data_4=file_data_4.convert('L') +test_img_4=np.array(file_data_4) +#выводсобственногоизображения +plt.imshow(test_img_4,cmap=plt.get_cmap('gray')) +plt.show() +#предобработка +test_img_4=test_img_4/255 +test_img_4=test_img_4.reshape(1,num_pixels) +#распознавание +result=model_100.predict(test_img_4) +print('Ithinkit\'s',np.argmax(result)) +``` + +![Отображение "4 повернутой"](images_for_report/19.png) + +**Вывод:** модель неустойчива к повороту изображений, так как не обучалась на повернутых данных. + +--- + +## Заключение +Изучены принципы построения и обучения нейронных сетей в Keras на примере распознавания цифр MNIST. Лучшая точность достигнута простой моделью с одним скрытым слоем из 100 нейронов. При усложнении архитектуры наблюдается переобучение. Сеть корректно классифицирует собственные изображения, но ошибается на повернутых. \ No newline at end of file diff --git a/labworks/LW1/Копия Untitled0.ipynb b/labworks/LW1/Копия Untitled0.ipynb new file mode 100644 index 0000000..6e8c00f --- /dev/null +++ b/labworks/LW1/Копия Untitled0.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"gpuType":"T4"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"},"accelerator":"GPU"},"cells":[{"cell_type":"code","source":[],"metadata":{"id":"1TFPbD2koKmu"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["from google.colab import drive\n","drive.mount('/content/drive')"],"metadata":{"id":"RtZRG8oCnmmC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1) В среде Google Colab создать новый блокнот (notebook). Импортировать\n","необходимые для работы библиотеки и модули.\n"],"metadata":{"id":"5oURju7duPmk"}},{"cell_type":"code","source":["from tensorflow import keras\n","import matplotlib.pyplot as plt\n","import numpy as np\n","import sklearn\n","from keras.datasets import mnist\n","from sklearn.model_selection import train_test_split\n","from tensorflow.keras.utils import to_categorical\n","from keras.models import Sequential\n","from keras.layers import Dense\n","from PIL import Image"],"metadata":{"id":"09gFd_-eo7eW"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2) Загрузить набор данных MNIST, содержащий размеченные изображения\n","рукописных цифр.\n"],"metadata":{"id":"mheOTPt8uTD2"}},{"cell_type":"code","source":["# загрузка датасета\n","(X_train, y_train), (X_test, y_test) = mnist.load_data()"],"metadata":{"id":"9k2EoBu8pKS0"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3) Разбить набор данных на обучающие и тестовые данные в соотношении\n","60 000:10 000 элементов. При разбиении параметр random_state выбрать\n","равным (4k – 1), где k – номер бригады. Вывести размерности полученных\n","обучающих и тестовых массивов данных.\n","k = 10"],"metadata":{"id":"foMRRdZ-uXOa"}},{"cell_type":"code","source":["# объединяем в один набор\n","X = np.concatenate((X_train, X_test))\n","y = np.concatenate((y_train, y_test))\n","# разбиваем по вариантам\n","X_train, X_test, y_train, y_test = train_test_split(X, y,\n"," test_size = 10000,\n"," train_size = 60000,\n"," random_state = 4*10 - 1)"],"metadata":{"id":"lmfDKm9yptVY"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод размерностей\n","print('Shape of X train:', X_train.shape)\n","print('Shape of y train:', y_train.shape)"],"metadata":{"id":"ycwVxkDzqYoR"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4) Вывести первые 4 элемента обучающих данных (изображения и метки\n","цифр)."],"metadata":{"id":"8qespHFRugQX"}},{"cell_type":"code","source":["# вывод изображения\n","fig, axes = plt.subplots(1, 4, figsize=(10, 3))\n","for i in range(4):\n"," axes[i].imshow(X_train[i], cmap=plt.get_cmap('gray'))\n"," axes[i].set_title(y_train[i])\n"," axes[i].axis('off')\n","plt.show()"],"metadata":{"id":"HLpjjwweqg_D"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["5) Провести предобработку данных: привести обучающие и тестовые данные\n","к формату, пригодному для обучения нейронной сети. Входные данные\n","должны принимать значения от 0 до 1, метки цифр должны быть\n","закодированы по принципу «one-hot encoding». Вывести размерности\n","предобработанных обучающих и тестовых массивов данных."],"metadata":{"id":"4rTauf-dunEM"}},{"cell_type":"code","source":["# развернем каждое изображение 28*28 в вектор 784\n","num_pixels = X_train.shape[1] * X_train.shape[2]\n","X_train = X_train.reshape(X_train.shape[0], num_pixels) / 255\n","X_test = X_test.reshape(X_test.shape[0], num_pixels) / 255\n","print('Shape of transformed X train:', X_train.shape)\n"],"metadata":{"id":"JJlSBKttun8W"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# переведем метки в one-hot\n","y_train = to_categorical(y_train)\n","y_test = to_categorical(y_test)\n","print('Shape of transformed y train:', y_train.shape)\n","num_classes = y_train.shape[1]\n"],"metadata":{"id":"Q5LqZcAdvhbl"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["6) Реализовать модель однослойной нейронной сети и обучить ее на\n","обучающих данных с выделением части обучающих данных в качестве\n","валидационных. Вывести информацию об архитектуре нейронной сети.\n","Вывести график функции ошибки на обучающих и валидационных данных\n","по эпохам."],"metadata":{"id":"NYYbUgM6xzEW"}},{"cell_type":"code","source":["model = Sequential()\n","model.add(Dense(units=num_classes,input_dim=num_pixels, activation='softmax'))\n","model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n","print(model.summary())"],"metadata":{"id":"IS8-6AUexljX"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["H1 = model.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150)\n"],"metadata":{"id":"IKRNkIbCC24a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод графика ошибки по эпохам\n","plt.plot(H1.history['loss'])\n","plt.plot(H1.history['val_loss'])\n","plt.grid()\n","plt.xlabel('Epochs')\n","plt.ylabel('loss')\n","plt.legend(['train_loss', 'val_loss'])\n","plt.title('Loss by epochs')\n","plt.show()"],"metadata":{"id":"kyd2Bh_hE9VO"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["7) Применить обученную модель к тестовым данным. Вывести значение\n","функции ошибки и значение метрики качества классификации на тестовых\n","данных."],"metadata":{"id":"Z2QVCB9NEzpM"}},{"cell_type":"code","source":["# Оценка качества работы модели на тестовых данных\n","scores = model.evaluate(X_test, y_test)\n","print('Loss on test data:', scores[0])\n","print('Accuracy on test data:', scores[1])"],"metadata":{"id":"NnPi_avSEuAy"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["8) Добавить в модель один скрытый и провести обучение и тестирование\n","(повторить п. 6–7) при 100, 300, 500 нейронах в скрытом слое. По метрике\n","качества классификации на тестовых данных выбрать наилучшее\n","количество нейронов в скрытом слое. В качестве функции активации\n","нейронов в скрытом слое использовать функцию sigmoid."],"metadata":{"id":"ukflwBJgGhu5"}},{"cell_type":"code","source":["model_100 = Sequential ()\n","model_100.add(Dense(units=100,input_dim=num_pixels, activation='sigmoid'))\n","model_100.add(Dense(units=num_classes, activation='softmax'))\n","model_100.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n","print(model_100.summary())"],"metadata":{"id":"VvgnJtzaGi-V"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["H_100 = model_100.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150)"],"metadata":{"id":"foBFtG3hHNsM"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод графика ошибки по эпохам\n","plt.plot(H_100.history['loss'])\n","plt.plot(H_100.history['val_loss'])\n","plt.grid()\n","plt.xlabel('Epochs')\n","plt.ylabel('loss')\n","plt.legend(['train_loss', 'val_loss'])\n","plt.title('Loss by epochs')\n","plt.show()"],"metadata":{"id":"zHA_blqiJm7-"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Оценка качества работы модели на тестовых данных\n","scores = model_100.evaluate(X_test, y_test)\n","print('Loss on test data:', scores[0])\n","print('Accuracy on test data:', scores[1])"],"metadata":{"id":"rxwTYECGJsAi"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["300"],"metadata":{"id":"gcDXa-faJ-Xp"}},{"cell_type":"code","source":["model_300 = Sequential ()\n","model_300.add(Dense(units=300,input_dim=num_pixels, activation='sigmoid'))\n","model_300.add(Dense(units=num_classes, activation='softmax'))\n","model_300.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n","print(model_300.summary())"],"metadata":{"id":"CcIlDKU4J5Fy"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["H_300 = model_300.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150)"],"metadata":{"id":"5dChQjjIJ5Fz"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод графика ошибки по эпохам\n","plt.plot(H_300.history['loss'])\n","plt.plot(H_300.history['val_loss'])\n","plt.grid()\n","plt.xlabel('Epochs')\n","plt.ylabel('loss')\n","plt.legend(['train_loss', 'val_loss'])\n","plt.title('Loss by epochs')\n","plt.show()"],"metadata":{"id":"iTj6TcVzJ5Fz"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Оценка качества работы модели на тестовых данных\n","scores = model_300.evaluate(X_test, y_test)\n","print('Loss on test data:', scores[0])\n","print('Accuracy on test data:', scores[1])"],"metadata":{"id":"AaTfpYqZJ5F0"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["500"],"metadata":{"id":"ROIhv1chKtlU"}},{"cell_type":"code","source":["model_500 = Sequential ()\n","model_500.add(Dense(units=500,input_dim=num_pixels, activation='sigmoid'))\n","model_500.add(Dense(units=num_classes, activation='softmax'))\n","model_500.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n","print(model_500.summary())"],"metadata":{"id":"APtFO2PMKu6W"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["H_500 = model_500.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150)"],"metadata":{"id":"vC0VRA8yKu6W"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод графика ошибки по эпохам\n","plt.plot(H_500.history['loss'])\n","plt.plot(H_500.history['val_loss'])\n","plt.grid()\n","plt.xlabel('Epochs')\n","plt.ylabel('loss')\n","plt.legend(['train_loss', 'val_loss'])\n","plt.title('Loss by epochs')\n","plt.show()"],"metadata":{"id":"yEM-YlO1Ku6X"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Оценка качества работы модели на тестовых данных\n","scores = model_500.evaluate(X_test, y_test)\n","print('Loss on test data:', scores[0])\n","print('Accuracy on test data:', scores[1])"],"metadata":{"id":"wtNPbUklKu6X"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["9) Добавить в наилучшую архитектуру, определенную в п. 8, второй скрытый\n","слой и провести обучение и тестирование (повторить п. 6–7) при 50 и 100\n","нейронах во втором скрытом слое. В качестве функции активации\n","нейронов в скрытом слое использовать функцию sigmoid."],"metadata":{"id":"oxK9QRg7Muj9"}},{"cell_type":"code","source":["model_100_50 = Sequential()\n","model_100_50.add(Dense(units=100, input_dim=num_pixels, activation='sigmoid'))\n","model_100_50.add(Dense(units=50, activation='sigmoid'))\n","model_100_50.add(Dense(units=num_classes, activation='softmax'))\n","model_100_50.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n","print(model_100_50.summary())"],"metadata":{"id":"_nawrX4iNBHW"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["H_100_50 = model_100_50.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150)"],"metadata":{"id":"sAb7w7eINBHX"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод графика ошибки по эпохам\n","plt.plot(H_100_50.history['loss'])\n","plt.plot(H_100_50.history['val_loss'])\n","plt.grid()\n","plt.xlabel('Epochs')\n","plt.ylabel('loss')\n","plt.legend(['train_loss', 'val_loss'])\n","plt.title('Loss by epochs')\n","plt.show()"],"metadata":{"id":"xXFa8Ob6NBHX"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Оценка качества работы модели на тестовых данных\n","scores = model_100_50.evaluate(X_test, y_test)\n","print('Loss on test data:', scores[0])\n","print('Accuracy on test data:', scores[1])"],"metadata":{"id":"CoZo6w5qNBHY"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["100 на втрором слое"],"metadata":{"id":"9lx5dZCGN5rS"}},{"cell_type":"code","source":["model_100_100 = Sequential ()\n","model_100_100.add(Dense(units=100,input_dim=num_pixels, activation='sigmoid'))\n","model_100_100.add(Dense(units=100, activation='sigmoid'))\n","model_100_100.add(Dense(units=num_classes, activation='softmax'))\n","model_100_100.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n","print(model_100_100.summary())"],"metadata":{"id":"bymnTOnJN29P"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["H_100_100 = model_100_100.fit(X_train, y_train, batch_size=256, validation_split=0.1, epochs=150)"],"metadata":{"id":"0SaEjqzoN29Q"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# вывод графика ошибки по эпохам\n","plt.plot(H_100_100.history['loss'])\n","plt.plot(H_100_100.history['val_loss'])\n","plt.grid()\n","plt.xlabel('Epochs')\n","plt.ylabel('loss')\n","plt.legend(['train_loss', 'val_loss'])\n","plt.title('Loss by epochs')\n","plt.show()"],"metadata":{"id":"HTzEyc5SN29Q"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Оценка качества работы модели на тестовых данных\n","scores = model.evaluate(X_test, y_test)\n","print('Loss on test data:', scores[0])\n","print('Accuracy on test data:', scores[1])"],"metadata":{"id":"MfOcXeXhN29R"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Таблица с наилучшими архитектурами сети и вывод по ним.![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8MAAAD3CAYAAAA5doYQAAAgAElEQVR4Xu29DbBmR3nf+dwCBAYW7MRG2Iu0c0cimzuMnIwC8qARKbOOkOYO7C4DxEEXSSmrSoSSkyyakbwOEptFIlU7zAhvOVpWSuQgDXfsjcQAgbkjhG2UlAbJ2EghI+YaR5o7HpUxggDBxhBkXHff8/W+ffp0n9PnvOe7f1PlMrrvOd39/J7++nc/3Wdhc/JP+AcBCEAAAhCAAAQgAAEIQAACEPCIwAJi2CNvYyoEIAABCEAAAhCAAAQgAAEIhAQQw1QECEAAAhCAAAQgAAEIQAACEPCOAGLYO5djMAQgAAEIQAACEIAABCAAAQgghqkDEIAABCAAAQhAAAIQgAAEIOAdAcSwdy63G/zYY4/Jzp07IQIBCEAAAhCAAAQgAAEIQGD0BBDDo3exu4FNieFvfetb8vKXv1ye//znuxeGJyEAAQhAAAIQgAAEIAABCDRIADHcINyhJV23GP76178uDz70WfnhD38oLzznhfL3fuEX5FWvetXQsFBeCEAAAhCAAAQgAAEIQGCEBOoRw2d/S/7Je++XP0kBeqlceOW18o9W/idZfLFO7jn56m9cLyu3HZdnvj/57Sf/jtzwax+V91/+ihEiHo5JdYvho5/8hHzzm98Md4W/+93vyktf8lJZueqq4QChpBCAAAQgAAEIQAACEIDAaAnUI4a//Ctywd8+ID947V55/fkBq7+QP37892X9mW/L95+3KNf+1mPy0bcmQvc5+YNf+VnZeei/yGve9U/lH1/2UvnPR39dfu34t+Xyw38kn3kXgrir2lanGP7Rj34k9/yb3wiF8EXbt8sjJ04ghrtyLPlCAAIQgAAEIAABCEAAAhkCtYrhpcObEzGr5PH9Dbn77++Qdz/4Snnfl/5Qbv9bk9+e/oD87IUH5KfvOS2f/SVFIN+4JK+7e6d8+nur8mYc1QmBOsXw1772Nfn0sc/IhRdcKG+47DL5yle+Iq9+9avlpS99aSe2kSkEIAABCEAAAhCAAAQgAAGVQLNiOMjpuYfl3VveKKtvOCrf/v/eKud87M2ycPVfyj0//Kz80jlKUf7gRtnyuk/JL/7Hp+X/CkQz/1IEvvlfvimBwCz6t+V/2BLuxlb5V4cY/tqfRmU8c+aMnHzySVn6H/+mXPjqC6fF+bEX/Zj8xE/8hCTPJT8873nPk3NfcW6VYvMOBCAAAQhAAAIQgAAEIACB0gSaF8OTIn35Vy6Qv/1v/p58/ht3yc9PBPHz/8Efy21//Lj8ahhSHf97+N3yijfeLZfou8ulTRrnCz/4wQ/kf/9n/0xOrZ+yGrjr0kvl1vfdIoGwrPJvXjH8F9//vnxs9WO5WQc7xa+ffL7psPbcS178EnnXykqVYvMOBCAAAQhAAAIQgAAEIACB0gRaEcMS7gaLHN78jLzrOx+TN593tTzy8/fIk0d/SV4V7A5//1G58eI3yIe/+tfk+s9/Q+76+dJ2ePFCniCeVwgHAOcVw8Gt0Z996KHQF3/69T8N//9Pv/Kn5fvf/wv57p/9Wfjfr/07r5Xtr3mNfPwTR+XP//zPp8+86EUvkjddfrkXfsRICEAAAhCAAAQgAAEIQKB7Au2L4YnN3/jEP5Sd/+Be2ZCXySt+/PnyvW99T7a+4WL5k4dfIB/49n+QX/6J7sH0tQQmQVyHEK5DDCfMNjc35V/9638tL37Ji+VdV63Ic889J5/45Cflv373v8q2pW3yt372Z+WTn/qU/OC//UB2/tzO8L/5BwEIQAACEIAABCAAAQhAoE0CrYjh7/zLvyt/7X/76/JbP/qE/GJi3eRyrd/9d78jp7/3Crnof/m78rVffpW84xsH5Zuf/0eCFs6vAqogrksI1ymGv/GNb8gnPvVJCc4vX/GmN4XGfO9735MHjn48/ObwOS84R577y+dk27bXyBt27WqzvpMXBCAAAQhAAAIQgAAEIACBkEALYvg78v++8afkPd+9bfK5pV8V9Zhw4oPnJueFt7zx0/KWz5+ZhEirt2rhJRuBQBD/2wfuD3deq54R1tOeN0w6Se8rp74Sfkrpkte+Tnbs2DHNJvjmcPDt4eBfED79P7/lLTgYAhCAAAQgAAEIQAACEIBAJwQaF8PfmJwX/htXPyyXHX5m8tml7J7vc1/9l3LFz/1j+eovfl7OTA4LI4U7qQdhpnWJ4Yf//b+Xr/7RV2X5yt1y3nnnTQ167Pd+T778n74c/vfzn/98ecfb3i4ve9nLujOYnCEAAQhAAAIQgAAEIAABbwnUKoZfct2/kn+yM2H55/Kfj/66/Nrxs/Lf/a8flVOfeJckXxVOnvjG535ZfuHNd8ozlx+WP5p8oFj/3VuvdGR4XWL4gY8/IN/69rflH15zrbzwhS8MrXn69Gn57d/5bXnBC14gF2y9QP7wq38oP/7yH5e9b31r+Df+QQACEIAABCAAAQhAAAIQaJNArWL4dKrk58jLtlwkb/3Vj8r/c/12eXHGqi/LLX/zUjmy82Py2EffihBu0+uWvOoQw3/1V38l9/zGb8hLXvpSWXnnO8OcgouzPv7xo/KjH/1I3rxnj/zMz/yMfPoznwlvnD7/vPNl95VX9sB6igABCEAAAhCAAAQgAAEI+ESgHjFcldjkluHnzjmH0Oiq/Gp+r6oYDgTwf/zyl+WV554rz5uEP3/q331Kti5unfzfovz27/5OqpTBd4Z3Tr4zrH+P+CUvntw8vfKumi0iOQhAAAIQgAAEIAABCEAAAmYC3YphvNIrAlXFcCCEf++Lvxee/w2+IfyFRx+Vn7vk5+Snfuqn5Etf+lLKxle96lXymm3bpt8jTn7kO8O9qgoUBgIQgAAEIAABCEAAAqMngBgevYvdDZxXDP/Yi35MzjnnBfLdP/szedvevfKTf/0n3TPnSQhAAAIQgAAEIAABCEAAAi0SQAy3CLvvWVUVw0GY9NqDD8rXvvYnoYl/48JXyxvf+Ma+m0v5IAABCEAAAhCAAAQgAAGPCSCGPXa+bnpVMZyk8+3vfEf+8i+fk3NfcS5UIQABCEAAAhCAAAQgAAEI9JoAYrjX7mm3cPOK4XZLS24QgAAEIAABCEAAAhCAAASqE0AMV2fHmxCAAAQgAAEIQAACEIAABCAwUAKI4YE6jmJDAAIQgAAEIAABCEAAAhCAQHUCiOHq7HgTAhCAAAQgAAEIQAACEIAABAZKADE8UMdRbAhAAAIQgAAEIAABCEAAAhCoTgAxXJ0db0IAAhCAAAQgAAEIQAACEIDAQAkghgfqOIoNAQhAAAIQgAAEIAABCEAAAtUJLDz88MOb1V/nTQhAAAIQgAAEIAABCEAAAhCAwPAILPy3Hz43KjH8xONfynhh586dw/MMJZ6LwInHviC7dl46Vxq8DAEIDJMA7X+YfqPUEGiDQNA/vPxVzAvbYE0eEBgCAcTwELxEGUsTYDJcGhkvQGA0BGj/o3ElhkCgdgKI4dqRkiAEBk0AMTxo91F4GwEmw9QNCPhLgPbvr++xHAJFBBDDRYT4HQJ+EUAM++Vvb6xlMuyNqzEUAhkCtH8qBQQgkLdYTpg09QMCEEgIIIapC6MkwGR4lG7FKAg4EaD9O2HiIQh4SYCdYS/djtEQsBJADFM5RkmAyfAo3YpREHAiQPt3wsRDEPCSAGLYS7djNAQQw9QBvwgwGfbL31gLAZUA7Z/6AAEI2AgghqkbEICASoCdYerDKAkwGR6lWzEKAk4EaP9OmHgIAl4SQAx76XaMhgA7w9QBvwgwGfbL31gLAXaGqQMQgIALAcSwCyWegYA/BNgZHqmvn7r7WnnPUZG333mvvPuCkRqZYxZi2DefPyjvu/LD8kXd7Ne9Vz5325W+wfDeXtq/91UgBqD3C5fIjQ/eJrvB4zUBxLDX7peNO6+TvUeezUC47NbPyK8zXfCyciCGR+n2p+Sua2+Ts+eLnD3vVjl8/YWjtDLPKCbDvrk8mvTKjZ+VD74psT3629m9d3rZBnyrAewM++xxg+1P3y1X3/BxEaX9R4vE5yOIPa8qiGG/K0AihlXxm/ztv7/q/5bP3ODhDpLfVUIQw2OsAA/dKpevnicfWXlG3nPHRB94uBKOGB5jxc6zySSGRY7feoXcIewO+1YbaP++eTxrr7ntBwvFN8gju1gg87mGIIZ99r5Md4bTO8FPyx1v/6dy+E9fK//ixD8nesSzKoIYHqHDg0nAkfOCwf4pw27ZCA02mMRk2A8/z6y07wynd4t94+KnvbR/P/2e3x/4zgT7EwKIYb/rgmlnOCAS/V3k6sP3yI1b/Wbkm/WI4dF5PBAFvynnx2eFw7CwZ97p3blJJsOjq9gFBpnPDL+SEGnfKkJoL+3fS7fPjA5DpE/IZZ7emeG59wvNRwwXIhr1A/li+Fnh7PCo3W80DjE8Np8nIdL3Xi/hSeFwUvCMXOVZqDST4bFV7CJ7TDvDUUjkA+cTJl1Eb2y/0/7H5tGS9iCGSwLz63HEsF/+1q1FDPvtf5P1iOFR1Yl48p+9JE982yFjMjyqiu1gjPnMsASLQ56em3eANtpHaP+jda2jYZb+wPFtHhs3AcTwuP1bZB1h0kWE/PsdMTwmn1t2gcNQ6RO75CPJbvGYbLbYwmTYAyenTEQM++bxPHtp/9QG2+V5XKpH3UAM+10HzGKYC7R8rhWI4RF533o+2MOQMSbDI6rYTqYQJu2EyZOHaP+eODrPTMOnlaJIkbPyds4Se11BEMNeu998m/SD/1x23PYHwqeV/KwbiOHR+D0KkT67on5nNTHOv7OTTIZHU7EdDTFfoCXnvs2riAhHWKN/jPY/ehc7Gqj3C5d4+alBR1jePIYY9sbVRkOTnWH9Ry7O8rdeIIb99f2oLWcyPGr3YhwEcgnQ/qkgEICAjQBimLoBAQioBBDD1IdREmAyPEq3YhQEnAjQ/p0w8RAEvCSAGPbS7RgNASsBxDCVY5QEmAyP0q0YBQEnArR/J0w8BAEvCSCGvXQ7RkMAMUwd8IsAk2G//I21EFAJ0P6pDxCAgI0AYpi6AQEIqATYGaY+jJIAk+FRuhWjIOBEgPbvhImHIOAlAcSwl27HaAjYd4YfffTRzbHz2blz59hNxD6NAJNhqgQE/CVA+/fX91gOgSICiOEiQvwOAb8ILCCG/XK4L9YyGfbF09gJgSwB2j+1AgIQsBFADFM3IAABlQBimPowSgJMhkfpVoyCgBMB2r8TJh6CgJcEEMNeuh2jIWAlgBimcoySAJPhUboVoyDgRID274SJhyDgJQHEsJdux2gIIIapA34RYDLsl7+xFgIqAdo/9QECELARQAxTNyAAAZXAwsMPPzz6C7Se/8IX4HUIQAACEIAABCAAAQhAAAIQgMCUwMLm5N+YebBDMGbv2m1bWFiQkVdtPx2L1RBwIED7d4DEIxDwlAD9g6eOx2wIWAgghqkaoyTAYDdKt2IUBJwI0P6dMPEQBLwkQP/gpdsxGgJWAohhKscoCTDYjdKtGAUBJwK0fydMPAQBLwnQP3jpdoyGAGKYOuAXAQY7v/yNtRBQCdD+qQ8QgICNAP0DdQMCEEjNGTgzTIUYIwEGuzF6FZsg4EaA9u/Giacg4CMB+gcfvY7NELATIEya2jFKAgx2o3QrRkHAiQDt3wkTD0HASwL0D166HaMhYCXQqhg+fusVcuS8O+Xw9Re25hJuk24Nda8yYrDrlTsoDARaJUD7bxU3mUFgUAToHwblLgoLgcYJtCaGAyF8x++LvHJvH8Twuuxf3CaHZJ+c2jgoSwnmJ/fL1osOyUbw37tXZXPtqsYdQAbNEDAPdvi9HO2I1/oHNuXY1ZM3D++RhfcvpdtMuQR5GgKtEKD914GZ9l8HRdLoH4FcMazOA8OiL8q+k6fl4Pb+2UGJIACBegi0IIYflPdd+WH54rmXyCXyRTm7q69i+IjsWViRNURwpZq1fvNW2fahJVndPCY7lP/d1XKC+2QYv+c6PDUxYFJQqXHwUusEaP81Iaf91wSSZPpEwCqGgwXfa9Zk8aZTcvpAtE0SzW02ZPm+eFG4T4ZQFghAoBYCrYjh4w9dKbvf9JTcde0N8khPxXDU4QkrgLVUq+4TcZ0M4/fufUUJIFA3Adp/3URJDwLjIZDbPyzpUYGWiLLx4MASCHhPoAUxnDDusxjO2x2MO8Izs7qSXiHM/j57smAnLV6F1GuhuioZ/RaXb/qg4w6dnn5q17tMuV3yL+KkpxEbs0ULVa+pSbpNhsfm99gH+mAe1oN1baGnwKd57yQ+i3eNlu5bFblmElWR+M4UXaHXRc3vamTBLJogKuO6skpf2Bac25Ra0WxtYTmMdLBGN1jyClJOt+GCtuHE0bWM7u0wu9MxqxOFuyB19S0F9aJq/0f7V2ot7V9rj/og49q2ZruE0xSKIsly+yOJjmspc4tUyaZp19F/xCk79cOTg2KGcTnZITX9liaqjy3pfvTI8oKsHDcP9EVzK1O/NC1X3vijZWfsH6b9sL4DrIth07iU1I0oOi5pfZmyKSHXIYd1ff5jStutT0+Pk3p5zHMD8663y3zPPH5m566zsruOiVlmal6TunRySW6ZHGfMn3e42avPO5K8w7JetN8+b8qbt+r9bdLmlL4ir16Y50Ime4rqRcRNzyvyg0vfI1G0rN5Uddszxwr0+Y9tUp/fT0xKnukfk/ZfWEc2V2Q1M3eczB7DvsesnxDDkzPDYt0Vjp2lOj8TRpPX6Ap2mk2TlDj9aaefVDRDQ8qbsGY7OV34OZbbKX87p1kZc4RN0YSigkB2mQyPz++OYtjqU6W+GurmdBKjieHgjL3uZ/W4QbYuJp3cbJLkJIZd6qJLm8rUp5yBRr9XQH03R2TMJiYObUMZTOwcXcro0l8pA5De7pSJcht9i0u9EJe6augfaP85YtiFKe0/c69IdiJlaG96XXTujyx9d7IQnjcHceo/TOG+tn446NH1CaMyMc0TAoa6FXGb9fVGEajPe1zsnpTS6pOCOUWZC7RSAikMnXYTw6YxTWUhTmLYYfxwKo+hfpnqjUvfYBs/g0WdHKE0E8MuNqlCLr3AMB0TcucdbvamfRSU6xZZSs6Hu/SBprlp6j3t3oWpOE3bpNYL8zFD3R43hpn2EftXUhsM+X2PcTMiaV+mBaRMWzZAKuwn3OybiX2tjpjaxHR+gxhWPKKtOFg6d/MEPemAk87dUVQWNprkgXRHa1491Fcq9cTNnXV4AdI1Eq9cupXbJX+bqEwPguYymdOvoH5dVn71labR+d1NDOuTk3jYSU/+jKub67K4ZWNywVy8mm3sWCeppd611EXtXRcx7FIXl5wEql6/8tqC3skq7zrkZQvDT/nAiWNxGW1n9Y3tcPeyyGR35nZlFyN47hYJ/r42WXW3nY+rq29xqxdOdbWsGA4mbcE/2r8S9aCNKbT/eEclbv+2XcOiiZ9DH5Hqf7WoHqc5iFP/4dbekvyWd6/J+vbZudlIgKzL0uTva5ndzFkDzNvtlLhPcRHD89u9lnvGt1gMp3et0ouDLmI4n3fQv678ZvHOsNP4UUkMJ+19URbPbEz7+2r9bTI2Lcvy8UkdUS4bC8v/5NLk75P6FAswN5uKxXBa0OnzDn28NNubqmdBW1UvCHXpA4vm9RK1m9k4W1wvDp6c3b8zW9JM2+PE0NJnhe/ev1e5CLWMGI71T9wHPGFc0LGl595PRAyym4mm+ukyd5wuYG1ZlI3J+G+6EI+d4cnOcOjQycRQ3w2xCjXDys8h4yA2786wvVLZBouwulnDfdSW6yKGXfI/KI+bbuYOsioURfpu9fwiOEnBZWdodH5PxH5umLSdeWZgmIZWR/Xg6DtOye1PbpuFdtnqmTo5u+ae8Ib2rLgyde55q3txWE/mPJcWDua8E1PUFooWnPT6bVrMists2l1WyxkOmAZGqUmuyf50Gc0Dk60drsre+ych6MlN4eGEarIqft9eOXqNyV+xfXX1LTabU3U4DtMy7PLk9n+TotL+bTvDtP/sKOMQdWEUtUFKlsltkolzf2Qea53mIC79R9l++D6RFUUYRKLmdlmVFUNob2Js8SQ4JGaaQGuLCi52X3ef7Z6XAp9Y+wfL/CMT5uoihtNp6aHhwVzTLHrUtB3Hj+0u5dF8k2yMTEOOg8VPx74hg2mWdlA/bpkuoiS7otExqkgMu9pULIYzc4q88dJorzp3iOaxwRwnuTgtPX+1zIEKxPDFN0+0xaTV2L5MY6oXx8R0rE313w7z13D0OfcTpnRMBS4jhnPm7EpkWZiLNTqjqJ/ImXsZ+lMXMTxdAPjAumzLHBmMmCCGw08rJauA6tkWV4cUi8qo0w4/2BT/i7fpw8qaichXKlHFzqlotTosRXG5D8adrOmG7VkFjMXwGctAMg23Sq+0zp4uOJdpS7bg7y6T4dH53XDGIlPnEp9a+cX+UDqdqP5GQjUV2hUOPkdlb+azE8rgHJ67Ma3Sm8Sw2kaUkoeD6BPW296zIj6vTeUMBpk67HLm33wWOzXwF7WNcDJbwNF6xicpo2t/NfNNMOgGE9xwoE5WxT89EaDGxYuYW119S9z3ZcOx1XphObM0daG976D96/U8qSe2fjh5nvaf7TOTSbNpcdtFDLv0Rw6CXHVpZjGtzn446OuDM3dJyGgiamy7mUnB3Ba3i8WwW1+WnVel63z2/Ors9+Kd4XRa6SMdeW1IP/qTjGlx+1MXLnZEi6DpHU6DGC4aP3LHdFMEY9SvhmNUapHEsW/IDKFK3X3n6mx3NY4muD11frPgrKoWnm8UOi7zjmS8DBfPbfamz9Nm6ovLHMg0nVBFoXUhN6deGBclDGK4oF7YF4v0QueL4WzvpYy72nnh1Hlkw8ZFlHNRPxGXp7DeR6kVimG1jhsXGqJ0EMPJd4Yzq3+WFcyAWpM7w6mKEq8AFe2G6XW7rgnr9hI7w9aKnx4o9UsezGE5ph6m3N/cJsOJLyfNXem0XFalD1rY2MJXUqXPCZ2LFh4q+r3EzrDuhwzdaRlvl/WLVsQY4jaUnWHXzrdsdEdhCKR9NzvF24VjanBXgqeU+w7CVWhTCKMtQiMcJIIQLmVV3LqDFJe4rr6lxM5wYV01dA20//yd4UKmtP94khULYOsui4sYtlxeaLrQUuuDnMaiJnaG44XPcJcvXNCMjleZz7mmx/iiz1MWi2G3uZe6SFv2E45lxXA050sWdR12Ym2h63pfr4mJhKSbqMifW6VFwmwud2r7LbMw2VR5infUzbMwfQEzWkSZ7YoqYtQyjtlmd3Yx7B5JZbc3uzOcivB06QNNBVfG28yY7FovMpfmxhkVzA/V4jjNRSM5Ge00Z+bw5vowm7PbokKLdn4dxXChpnATw2E0Y7I7b43waVUMlxMzdT194rEvyK6dl2rJmVYek9WI2W6QU1y+0w6rxRqLY9TBIgrl1XdAclZOw6yKzyUcu9plZ1g/H53Ykc4/OjOcPVuZvZxAvxlYX1ioy+tuYZLxVwTjG+vG4HdLJ6TVM9sEK/X3+J3UGeGgZqkhbiXOqmUmSFXPDBe1BYc2Ffk9NWyYB4OikOBCMbxkWbXUVjOdOFp8q5TR7ZxNdudh/R37ZP1D8c6SVaTmT7zSRzNc+hbLgKixcKqr84jhaTQF7Z/2r4Uzqu3fuIuXjF8551Od+yOXNjOr6OXvHHBrb6YzlPuWDsmheDJZdMdH7r0O8eTWRQw7zb0KFhHt9x5Y5gc5C33p8jiIYUta6R1m03wnnbbtOIjL3Moohic7r+oZYf1IXbX+Nl13w7sntu+TpQ9Ndr3Dc+JVbMoROmXGywJ7TVFl02gllzlQgRg+GI+n093/yvXCFElXMOfOvedAXaArJ4Znm4HRRoltbreRc4ldUT8RLmAUagoHMayfEUYMu4jhCdhklW56sUo8gLR5m7S+i5WUae7bpHUB7Tj4OuVv4JTpsIpWmXI+YVNBIzvvDAVpj8bvbmLYdENveuV7NsnTbxU1ieENNbTJqb4kC08t3Sbd2c7w7ObRNbUP0dvGdHdACcvOcHRpry79lWlionxKpWgBIFhHDhe/NpQ7Fqr1LdZ0zhjCsNSB1WF3mvZf7jZp2n92Z0QXZJEAVY9OGNqbPlYVRgFNP8KTuzuT6j/i+j8N63TqP8rcJp1Msmdhs4lAKBLDLre/u4jhaShl7tzLdJt00UZB5CDbznDWx8pYOO2DHMSwYRw034KsVxg97epzK6MYPjPJT+1LbTvVpfpbbWyahgkn/XgVm4rFcP68Qwm1zbFXX2xILTJN7UgflypsA1qbT/UjsThOCUUlOsD+FQd9/HepF663rZcTw5mdYXW8Vo/q5d3obp0nJkdR3OwLaklemHQQ4p0Kf0cMO4phZaI3A6jHr+s7CKbPEOSdMVI6P/VsgdonZm451c9yOJ6z1dOPK2cyCc1+PsFWbpf8s3H+phsYs+cPHL+ZXFIQl5oMj8bvjmI4ZKn7VPNDUne0Ds0khpduCnYWD01umY7+Gc9qWepi4tbCcx/hJy1M5dbagnObUiuU/YxK7vd2HXaG4yHd+r288PdkQpLL0bWM9v5K5TcNk7UI87xdlTCduvqWgnph9nlxn0H7r+M7w+njI2HrM0SG+NT+Z2NnTl+ndi3O/VFeaGFBm3bqP+JCleyH9WNMhUIgr49W8s70q8YFrqK+LO5d48W5KfaCzyoFz+WGSRt8Vv426Vm/PrsJIxirou+f2kPJTULbbW7l9J3hM1rfaVz8LJgbqPU7/N8WoZa7eFBkk+pb86eV8vudJP18e7PzDiWCIjj/HNzpkzcHyrBIxkbDzqv2FY5y9cLUP5RhOMvN+i1oS5h0/pzdXIbwpvRMFJ8Oq0hXlLHPfPnqJGYn9d3v9BHXdHlaPDNsqjXN/80cJt18vuTQLYHSZ4K6Le4wc3fYRRymYS2XGo61A6f91440myD1tgXIDlngBwdI2sR3YUE2NzdLv8cLPSBAfe+BE8ZXBMTw+JI4ZZcAACAASURBVHyKRRMCTIZbqAYMSvVAhmM9HJVUaP+1I0UMt4C0Uhb0H6Wx0T+URtafF6jv/fHFiEqCGB6RMzFlRoDBroXawKBUD2Q41sMRMVw7x9wEqbft8rblhh9K+4H5QWlk/XmB+t4fX4yoJIjhETkTUxDD1AEIQIDIEOoABCBgJ4AYpnZAAAIqAcQw9WGUBBjsRulWjIKAEwHavxMmHoKAlwToH7x0O0ZDwEoAMUzlGCUBBrtRuhWjIOBEgPbvhImHIOAlAfoHL92O0RCwi+FHHj0x+iv1Lnv9LqoABCAAAQhAAAIQgAAEIAABCEBgSoCdYSrDKAmw8jtKt2IUBJwI0P6dMPEQBLwkQP/gpdsxGgL2neHJt9ZGvTPMd4b9rP0Mdn76HashEBCg/VMPIAABGwH6B+oGBCCgEmBnmPowSgIMdqN0K0ZBwIkA7d8JEw9BwEsC9A9euh2jIcDOMHXALwIMdn75G2shkFrlXViQkQc94XAIQKAiAeYHFcHxGgRGSoCd4ZE61nezGOx8rwHY7zMB2r/P3sd2COQToH+ghkAAAqkFdM4MUyHGSIDBboxexSYIuBGg/btx4ikI+EiA/sFHr2MzBOwEWtgZflDed+WH5YtJGc59m3zk3uvlwpa8wgVaLYHuWTYMdj1zCMWBQIsEaP8twiYrCAyMAP3DwBxGcSHQMIGGxfBTcte1N8gju+6Uw9cH8jf67wfOf6987rYrGzYtSt5LMfzkftl60SHZSAjvXpXNtata4d2XTBjs+uIJygGB9gnQ/ttnTo4QGAqB7vqHddm/uE0OyT45tXFQloYCrOKccv3mrbLtQ9OZqCzedEpOH9CsPrxHFq5ZU0gsy+rmMak8Y1XKunzfphy7eiiQuypnXCfPJPk78tf8ZvStYtKR5QVZEYMW0euWLMq+k6fl4PZ2eTQshrPGPHX3tfKeE7ta2x32TgzHFWtp2gkckT0LK7LmmSDubrBrtwGTGwQgkCVA+6dWQAACNgLd9Q8DFMMV55SREJaZsElEjzIXTcSyKlpD0XS8uiBK8l3csjHZEBrYokPrTTauj0szkRrxzxfEWb/l64zpooiuQ2JBrQppU51oAwtiuA3KreVh6WjDCrfeyWpLa6ZrGXU32HVlMflCAAIJAdo/dQECEEAMz1sHqs4pI3G0ru0ER0JnKd75zQqxqLTmd90smaV5avstaTHuloBXT2UWLJz4W4SvUWdou86aGA6F97q+YGGrF826pmUxHJ0fPrs3CZtu1rggdb92hm2dyDydS/M+aiIHJsNNUCVNCAyDAO1/GH6ilBDogkB3/UOJnWE9fHiLRTScUQiaxMZx5XctjeJdwHrnlGkxbPO8LrZKRDfGzKKd5vx5b2EIt84/s6OdiPrEDq2c4fuTnfGb1uVQHCqe7IDreYsxNDhOb4pptltr85sqLkXfmTfgNovRyXKEUaTGCWQiBdL2zxZAEiEclPugPB4cD1B2oO3tvkQbqbHzaFEMx+eFhQu0avRfOqmCSupTqHR3g11j3iVhCEDAkQDt3xEUj0HAQwLd9Q9uE/1sqKgqLILztKZ00uIvK5gq7LjVOac0hMQaq16cp5jOFxfUVd3mXNGohmJreRaFAZtFvUkMT85CawsQpncz5TSElKeeSYl+mxgtatj2+pC7SFKpTpSpeyUWP4pMLPF7S2K4GyEccPBqZ9haSctUxBK1p8ePdjfY9RgKRYOAJwRo/544GjMhUIFAd/2Dixi27GimBNsTxjDkGYqa5nx1zCnVC5Iyu9u683TRX8a5Bm4m0WixKRSp9++dXGx2sew3hHhLvNMbXO61IxXunRaj002nMoJVK5N5ZzayT5Rd79QGV+njkPY6kr+Dn18/N4z3E7nXx3nPjJepMeqzLYjh9m+QVg1EDAc03Cti1YrUt/e6G+z6RoLyQMA/ArR//3yOxRBwJdBd/+Aghh0FaCQaAovNlx3NQnGrX0YljmVx5V4kdBKbqtwCnXf+dU0V4UWi0WqzstTgLIbz7+qZ+TBKO7Lbbb6uC9bc0Gajg6qK4YmiiG8Jn/lJCemeQwwn6RbdTO1a38o817gYPn7rFXLH2XZDoxHD+nXy3YQdlKmIdT/b3WBXtyWkV4aAPrjYJgpl0uTZ4RGg/Q/PZ02U2O1sXhM5k2afCXTXPziIYeOOYkDTIF6KPks072drKoXE5nnePhedRwhP2Zyx5T1bEDCLZuU9K/96xHC6T4rLJdHnUKOvwDjO11O+qXIvUMUw6RhD2o6ic8HFAr9LIRyY1LAYji7M+mKmfl4iNz54m+xuobf0amfYegtflYbSgnMazKK7wa5Bo0gaAhBwIkD7d8LEQxDwkkB3/YODGK66GzsVvrbP4iS7d2V2iuu9QCu5KTp9f83sxuEqO8JhBc4TsMbzwMonn/QW0KQYtp2HNgjb4jt+FIH5ztVKX4ypdIGWtcdQw7j1h/LFcLIQ0sWOcFLShsVw9/2sX2LYUuGKwkK6d1PtJehusKvdFBKEAARKEqD9lwTG4xDwiEB3/YODGI43NTJiyOFiqTp2PdPVoOKc0iboMzYkQriMQM9W1PxbsbVzyLayTefJt8v6RdnPQqkh4wdPqp+IisujX3plmndbhLYeduz6yaEkVHp595qsyexbwa5NOe8iMP2zWLM0LQskuTqjaBc6CRF3LXn9zyGG62fabYqZG/scQy66LXXtuXc32NVuCglCAAIlCdD+SwLjcQh4RKC7/sFFDJvOZOoXS5nmdWra18k9wadsJP05puJPKRkqQcU5ZTavZGda/0TQfELYvNusSXrtjGv27HKap/U274SnVdRP8k3OzJrEoeGW6ERkb0xene6MG57LPROtvluqHcd2K2eqXepIRkQXLtSYxXCWc6nC1/owYrhWnD1JTD8nYjzQ3pOyNlSM7ga7hgwiWQhAwJkA7d8ZFQ9CwDsC3fUPs5BgI3R1rpbzndvoXf07tJM/pW5rNuWVDqF2ET5hVkVzSosYypzZV+3LnGfWiExtyd/QKdwNV1kpfOb5znCYpOaf5ftOydL7lW/p2nZKM3YHPlmR1clN0eloAPt3hlVSNh+6cQlS0uuJHmZv5q/zyw9xN4lhQ/1NVQFbuH8z3RViuBmupNoxge4Gu44NJ3sIQEBo/1QCCEDARoD+YWB1IxCQN18sp9euGljBmy5u8cVUTZdgLOkjhsfiSexIEWCwo0JAwF8CtH9/fY/lECgiQP9QRKhfvwe7kHvkmJw+sNSvgnVdmnCX+ajsPXlaDm7vujDDzh8xPGz/UXoLAQY7qgYE/CVA+/fX91gOgSIC9A9FhPr0e7D7uV8u3jgm7AvHflFCrSvfwN0nF/egLIjhHjiBItRPgMGufqakCIGhEKD9D8VTlBMC7ROgf2ifOTlCoM8EEMN99g5lq0yAwa4yOl6EwOAJ0P4H70IMgEBjBOgfGkNLwhAYJAHE8CDdRqGLCDDYFRHidwiMlwDtf7y+xTIIzEuA/mFegrwPgXERWHjk0ROb4zIpa81lr981dhOxDwIQgAAEIAABCEAAAhCAAARKEGBnuAQsHh0OAVZ+h+MrSgqBugnQ/usmSnoQGA8B+ofx+BJLIFAHAcRwHRRJo3cEGOx65xIKBIHWCND+W0NNRhAYHAH6h8G5jAJDoFECiOFG8ZJ4VwQY7LoiT74Q6J4A7b97H1ACCPSVAP1DXz1DuSDQDQHEcDfcybVhAgx2DQMmeQj0mADtv8fOoWgQ6JgA/UPHDiB7CPSMAGK4Zw6hOPUQYLCrhyOpQGCIBGj/Q/QaZYZAOwToH9rhTC4QGAoBxPBQPEU5SxFgsCuFi4chMCoCtP9RuRNjIFArAfqHWnGSGAQGT6AFMfyU3HXtDfLAszGr171XPnfbla2BO/HYF2TXzktby4+M+kGAwa4ffqAUEOiCAO2/C+rkCYFhEKB/GIafKCUE2iLQuBg+fusVcockAvhBed+VH5aze++Uw9df2IqNiOFWMPcuEwa73rmkvgI9uV+2XnRU9p48LQe3a8mGvx2SjeTPu1dlc+2q9EMuz9RXWlLqgADtvwPoZAmBgRBoq384srwgK8eXZXXzmGijUK9JReVOirgo+0xjrW6BPq5u2SenNg7KUuq5I7JnYUXWpn8rZrN+81bZ9qGl+Rge3iML1wS5OtrSa++0ULgpryivxZtOyekDaU+aShH5ajr7kuX7NuXY1eXnaOn6N3vfmF5NOBoXw3o50+K4JitykkEMN8+4jzm0Ndj10fZxlykZTA2DWjwYL0074PhZVRC7PDNugF5YR/v3ws0YCYFKBNrqH4YohsMyr8+EbCRwJF8Qx+OqTEXTuuxf3CaHzqhiNzseR3xyBOpUYBeL5ryKENm0KItnNmTDtEBeqRaN9KVQCK/P/J3xrdnujC9N7znNv+K6s2TYyGgQectiONoZlhs/Kx98U4NWKUkjhtvh3Ldc2hrs+mb3qMuTWq3UB9C4AxVtNTrVsbs8M2qC3hhH+/fG1RgKgdIE2uofBieG4zE2vQNXLE50AR06RBM+5h3eSCCvG3ceE0EdJDaPGJ7lcfuT2wa5U1+6gld+wbCBMEmrcHfeIpjT77nOv6IyiGlXubJdxS+2JobDHeHfnxTo3LfJR+69XtoJkhZBDBdXgjE+0dZgN0Z2vbQpHqTDcJ2L9qdXLsMC2wZV9e9PWAbevAG5lzQoVAEB2j9VBAIQsBFoq39wF8N6+HB2tzQTOqqHIethyoGEVAWFww6fTfQUiiET6MwuoOkh+9gb5nn/Xll9x1FZ0cKknXar4+xSz0p0jGoWPaaWqTiEWw8DnoUPWxYMtMWFxKZ9S4fkUBiGPvNzNjTYsACghS9Lsstt823KB2ahm/KKzWdFvtR3k5NEDflnFz60OpB3DK7BLq01MZzYEIris+0JYsRwg7Wnx0m3Ndj1GMF4i2bqeK2dtTIAHHjcMhA6DBLjpTlKy2j/o3QrRkGgFgJt9Q9OYjgRsUr4biK6EjGbTUcTXyYxZBMoOQSNO7yT58uIzyj5eEw1nhtOCmAKpY5/U8p+3X3znBnWdyMtu5MGH+jM88OAJQoL10N7TWI4OFOrhWpnuWfLqdeJKeMwrR1R/lpkXOlFjAJROwuD1yqRy3vX3OM0/0rq2uKWSUj7mSSf5s96ty6G5em75eobTshld94r776gln4tNxHEcPOM+5hDW4NdH20ffZlKiWFl0mAVw8VhYKNnOjIDaf8jcyjmQKBGAm31Dy5i2CxAVTF0ndxjEloqjwrC14TTJobFOX01tNkuYNRd0OylSOmdwtKCTjXMsEhuEvZmu5Vw3R3mHeVkp/fUhsVHRjGsnb+2LeSnmFt20MNnJLxcbEfmbHeFeY3VzwXRc7k2rEUXcFnFcLqcpnPk2YWAGjuDOKn2xfBDt8rld0yODT94m+yu355MiojhFiD3MIu2Brsemj7+IiGGx+/jOS2k/c8JkNchMGICbfUPxWLYLlhUERgJneCWXpvAVEJ857ggan4xrFQa9WiT7SZi245s5gKvardJG/ln8nQQjYWLASXCpHNvxlYXEwKWsb9zw7sT5qZwY1tIuKVxVxXDk+RsO+dhrS0hhs0ls+zo19hHNS6G07dHx98cPr+9bw0jhmusLQNKqq3BbkBIxlPUUmKYMOnxON7dEtq/O6sxP6mf8ePTKmP2trttbfUPxWLYfkQnsyOaORPscK64pDCuL0w68kWx/VoI9hPaTcaTNKrvDOtngPX6kZzJLT4mVRwmPp8YTp8XjsulznNCLmvmTxUpZqn+kyqfpHIJd875xFLKjjBE/mLZn1yQ5hgmbWvFLnXJvQfIPtm4GBaJBfCzceZcoDWPv3jXkUBbg51jcXisTgLGDpsLtOpEPPS0aP9D9yDlh0BzBNrqH4on8G47w9lvFOd8YjDGNl0IKiGIa71Aq4IYvvhm9fvGWf+7fu82eDNXwKbClzsWw8YbvCcGVBDDs3eOibzFcIa5qElVvUDLlm7qMiyXOZr9W8bFbanIuPzfWxDD8xVw3rfZGZ6X4DDfb2uwGyadgZfaKIbzVmaTb+a5PDNwNhQ/JED7pyJAAAI2Am31Dy4TePMzDmGhNhE1NdohDR1QmbFVzyfzXdh0/k9o3y9OXi9iVG1nuMj29AVf5rI53Dcy5WUWn/pZV5MtNtGeDju2CEnLd3vXdy+LHF+XvSdPy8HtZfoBcz6FPrCIaOOnlYyXjGlzNP0TmeIQyl7GTMOziOE5AfJ6Pwm0Ndj10/qRl8oWypM5o2RY8XV5ZuT4fDCP9u+Dl7ERAtUItNU/FAm9sPSFt0mbhV0qbZMwdviUUpZe9obn4hDhSSqG/JOQ2ekFWYbyJGIxb8e3UIiZqoCD7SmxGZ/J3cjc6D277Cp7sVN6fpHhpIS1JwyMtpjOVsd/U491ZC+RMteLaURA7k3e9naTyceBZZBaJsTeVCdd5l8GHqZLtaq1fPtbiOG6iZJeLwi0Ndj1wljfCpF3mYV+rsoUIubyjG9MR2Yv7X9kDsUcCNRIoK3+IX0WVDMgJVaKvnGrX6wUpKV9h3YqoGb5pESmo6iZCpvwO7jBP9vZZC3/zJlmw3dyk08uTYtY/MmcMrupSbLVFiGKfJCEXgdXQsVkgouhlDO0mbO/J5fkFuW7xlZhr/suqBufFtkzeTf1OSP9uZz5TfYzSMXh4FPDtHz0xYr83Wx7vQl/cZl/OdWlGjuESVKI4Xp5klpPCLQ12PXEXIoBAQgoBGj/VAcIQMBGgP5h+HXjyPJWefxA2TDg4dtdaEHhzdeFKXj5AGLYS7eP32gGu/H7GAshwGSXOgABCJQlwPygLLG+PR/scq7KyuT7utnLxfpW1nbLE+5Oy6psrkGmDHnEcBlaPDsYAgx2g3EVBYVA7QRo/7UjJUEIjIYA/cPAXTnZ/dx68mAqRHngFs1d/GmIdsWzwnMXYOAJIIYH7kCKbybAYEfNgIC/BGj//voeyyFQRID+oYgQv0PALwKIYb/87Y21DHbeuBpDIZAhQPunUkAAAjYC9A/UDQhAQCWAGKY+jJIAg90o3YpREHAiQPt3wsRDEPCSAP2Dl27HaAhYCSw88uiJzbHz2bXz0rGbiH0agWCw4x8EIAABCEAAAhCAAAQgAAEbAXaGqRujJMDK7yjdilEQcCJA+3fCxEMQ8JIA/YOXbsdoCNh3hjcn/8bM58RjXxB2hsfsYbNtDHb++RyLIZAQoP1TFyAAAesu0CRybORTX5wPAQiUIMDOcAlYPDocAkyGh+MrSgqBugnQ/usmSnoQGA8B+ofx+BJLIFAHAcRwHRRJo3cEGOx65xIKBIHWCND+W0NNRhAYHAH6h8G5jAJDoFECiOFG8ZJ4VwQY7LoiT74Q6J4A7b97H1ACCPSVAP1DXz1DuSDQDQHEcDfcybVhAgx2DQMmeQj0mADtv8fOoWgQ6JgA/UPHDiB7CPSMQLti+Om75eobTshld94r776gHRJcoNUO577lwmDXN49QHgi0R4D23x5rcoLA0AjQPwzNY5QXAs0SaFEMPyV3XXuDPPDsK+XtiOFmvUrqwmA3vkpwZHlBVo7P7Fq+b1OOXa3Z+eR+2XrRIdlI/rx7VTbXrko/5PLM+PB5ZRHt3yt3YywEShGYv39Yl/2L2+SQ7JNTGwdlqVTuXT4cl/tMUoZlWd08JtoImSng+s1bZduHpqOqLN50Sk4f0K12SdvlGRE9P+NYXwbj4T2ycM3a5I1F2XfytBzcXuZlD5+d8opsN/s7y6Wc347InoUVEdM8TstfpKiexvVqyTDfc3Rfe2L4oVvl8tWz8spnhZ1hR+fwWHUC8w921fPmzfoJREJY6RDjzjLVSccid2nauUad7ZoqiF2eqb/4pNgyAdp/y8DJDgIDIjB//zBEMZwVDJlx1eDDSODITEQmi8mphWaXtOPxeMtsASGT9iT/qEyKaI3zE6MAd6t0YZrri7J4ZkM2TAvkbsn48VQ4t1rP+LuIfzm/zRZF9IWORFCrf8+krXliKsLn8G1LYvhBed+VQXj0eXKEMGk/GlTHVs4/2HVsANnPCGQEbPRTNMAlA6tlcpLq2F2eAfwYCND+x+BFbIBAMwTm7x+GJ4ZNwnMyioYLxutWoWn+PUprabqr7JK2+RlNRFuEr55fuVoxs+H2J7elF9XLJeTB04YNhInVhfzL+E2LzEuLYdsOb049VdPruxh+6u5r5f+UW+XwL/wuZ4Y9aE59MHH+wa4PVlCGPAJpMWzrLNW/P2EZ+IsmBPhhaARo/0PzGOWFQHsE5u8fSohhPeRT2RmNLNZDhyd/0if1mbDRdLivWWimeabHy9lvtr/neUMXRy5pP5FavJ6lnkpL35VMHtMWxF3sTV5NPSvRMapZ9JhqZSwEp3/Khubaw8UtIi72WyL4wvfv3yv7lg7JofDI18yP+jEwY2iwXg+SemLbPU9xMwvdlJ8tGw9i+3vysqPfknTC3fkDj+f4Qq99trJH3I++Y1X23r8ih3odJh1cmvUBkf/j3uvlQi7Qaq+39zyn+Qc7zwH23PxMKI21s1Y6UWvn6zBI9JwHxUsToP1TIyAAARuB+fsHNzGcDflMhG8itEzpaIuzmqAK5bO2M1vsafuZSpdQ6VT6mSNKbmlLrhiOw7Cf0EJ0NTFcFKqb5aDztfjNEPqtc8kPA5boDLkuxkxiODh7rS12ZBcTsuXM1iV13rLDeIa9dD0pELVW/lXeKxLYqjMtYn/G7Tq5x8S/uGFMn2g8TPr4rVfII2/4rHzwTZM8EcMlXMOj8xCYf7CbJ3febYyAujKaexY4KYEyUFvF8PyXLzRmLwlXIkD7r4SNlyDgBYH5+wcXMWyJOEpN7G3RSjM3lBY0Rg/axzjn9NVw1NTutlvaOywCPiUybTu3pjtCXGqqQXBZzylPj1wlCSsXPO0w7ygnO72nNixizCiGlfPXQVY2UZgSmJa6FD4jYbh6xFdNu8K8xiZqi8Lpc21YM1/A5SyG9QWk2D+mI3D93RkOzgp/WL5oqLSX3BgLZJcKPcczfFppDngDfnX+wW7AxntRdK2DtHasiGEvqoNmJO3fR69jMwTcCMzfPziIYZcxafKlg1l4rOXGXEWEut7qm6XgJliLbpWeysTUJVeuadsu0ApuqdbDhbMXaIVPlbxEy7jrndkFdhCNVpFoWHRXv15hFMOzs9ZWP51Jfok55IZ3p8X79Py3s9hUSlFVDE+SsO2cW/3mWL6kfaTPFuuLAw4+LOgaGt8ZTuXPzrBbT81TcxOYf7Cbuwgk0DQBdYX9mnss508Ik27aDX1Mn/bfR6+0Xyb9jB+fVmnfB33Mcf7+wUEMG8KbIxaGiXvhp2Sy54rLCUO3UGZXMZxcvBV9qSEO0TXsymXFaPpcbmjDRfvTtxdPhVVcc8Jd6Itlf+5FX6Zapp8B1p9JFh+Kj0kVn1EucWZYuXgsvbiQ/FdcLlWYhuHja1L0iSk13FpKh9JP8q8S7qxgTZ17LvKbgxg2C2H98lRLmyrZ8SCGSwLj8WEQmH+wG4adXpfSKdyMC7R8rCO0fx+9js0QcCMwf//gIIYdd4YzJZ7uBNu/rZqIhDKC2OWSK/fvJacF5Dxpz0KNc77XHDI5KntLfCM4V8CmFio6FsO2RZMKYngmZo+JvMVwhrmoeVS9QMuWbp7fcsXwbPEnuwBQtMhR7VvS7YrhIkc08Dth0g1AHUCS8w92AzDSlyLaVitTg0jeymzyzTyXZ3yBOm47af/j9i/WQWAeAvP3Dw5iOD5nmfrOfVBo282/ikHFO5HFAk7nYz4bXPAlhQJxlFyo5JK2+RltTLbk53yueWp0kX/SIdvmm64djlhN5yZm8alfemWyw+brdNhx/vnz2e3Y8XO7l0WOr5daPIjQuX1Ky7aAo9/Sneu3osWiM2VE7dDCpOfpvSq+ixiuCG7gr80/2A0cwKiKbxjYktVz9SKPzCUbhgmDyzOjYuenMbR/P/2O1RBwITB//1AktqJSFN8mbRK16bSjcFft0iVrCHae9dkzuy43SdtDndWda5e0s0LLlH9ml7mKrQ4LDqaLu8JP/sRnfnWRmjkTqy12ZEStctY79WklPUzadDnYNGx+JgitdUmCMPLZrvr0aEjmE14uLcNQZx1YhjJavy28yG8WMZzl7FJuxHAhJcRwIaJRPjD/YDdKLIM2Sv8OnzFETL3xMrDW9BF2l2cGTYrC0/6pAxCAgI3A/P1D9gxvKi913NHPA2fGJEPYpyZksmffJ1+hvW9Tjl2tim5NMBuN18uth2Kbd5wz+ZvG1cz3kk1h3pqtFsGWHuuzO4RFO+cuIj/1zdtQAOt+KPOd4Qh2utyT908uyS3Kd42tO6V6HQm4fFpkz+Td1OeMCuvSpBBW8VoimkDLR59r5e9mJxWvYGfXJIb1uZleh60CHzFc2NsjhgsRjfKB+Qe7UWLBKAh4QYD274WbMRIClQjQP1TC1quXjixvlccPnJaD23tVrO4LU3jzdfdF7GMJODPcR69QprkJMNjNjZAEIDBYArT/wbqOgkOgcQL0D40jbjiDYJdzVVYm39d1vwG74SL1JPlwd1pm4d49KVbvi4EY7r2LKGAVAgx2VajxDgTGQYD2Pw4/YgUEmiBA/9AE1RbTnOx+bj15UE4fcL//usXSdZLVNES74lnhTgrdo0wRwz1yBkWpjwCDXX0sSQkCQyNA+x+axygvBNojQP/QHmtygsAQCCCGh+AlyliaAINdaWS8AIHREKD9j8aVGAKB2gnQP9SOlAQhMGgCiOFBu4/C2wgw2FE3IOAvAdq/v77HcggUEaB/KCLE7xDwi8DCI4+e2By7ybt2Xjp2E7FPIxAMdvyDAAQgAAEIQAACEIAABCBg3UDbnPwbMx4+rTRm79ptY+XXT79jNQQCArR/6gEEIGCd+E4Wy0c+9cX5EIBACQKESZeAxaPDIcBkeDi+oqQQqJsA7b9upkiPOwAAIABJREFUoqQHgfEQoH8Yjy+xBAJ1EEAM10GRNHpHgMGudy6hQBBojQDtvzXUZASBwRGgfxicyygwBBolgBhuFC+Jd0WAwa4r8uQLge4J0P679wElgEBfCdA/9NUzlAsC3RBADHfDnVwbJsBg1zBgkodAjwnQ/nvsHIoGgY4J0D907ACyh0DPCCCGe+YQilMPAQa7ejiSCgSGSID2P0SvUWYItEOA/qEdzuQCgaEQaEEMPyV3XXuDPPCsguR175XP3XZlK4y4TboVzL3LhMGudy6hQBBojQDtvzXUZASBwRGgfxicyygwBBol0IIYflDed+Vvyvl33ivvvqBRW4yJ+y2Gj8iehRWR+zbl2NXts+8yRwa7Luk3kPeT+2XrRYdkQ096yz45tXFQlpK/68/tXpXNtavSb7k804AJJNkeAdp/e6zJCQJDI9Bd/7Au+xe3ySHRxq2+A6w4Zq7fvFW2fWg2ai/edEpOH5iO1qHVR5YXZOV4FsBy1XmrUtbKafTdH7WWL66TZ5JEl2V185hos6Zsjof3yMI1a7O/m+ZaEmmQ6VP6fC18u2L+tTKYfI6x8e8MP323XH3DM3LVg7fJ7poL75Kcv2J4VsF87BC6G+xcaiXPlCYQdrzrsu/kaTm43fJ2PAguTQfRuCNWO2mXZ0oXjhf6RoD23zePUB4I9IdAd/3DAMVwxTEzEsIyG7MTkZoSTTGPJcOidcXqkuS7uGVjsng+sEWHijZXfy3LP1qcKBDEsRCeaQv7XGtD8Xc27fg9RSRn6k1140q92bwYfuhWuXz1PPnIvdfLhaWKVs/DXophbRUPMVxPXSKV7giEHeT9e9O7wKniWCYZKRHt8kx3NpJzfQS6m+zWZwMpQQACzRDorn8YmhiuOmZGImdd2wmOhM6SsvNYd/TiTNyd2n5LWow3U5UGnapZeJp9NzPUXCf0tMyiOp22Of/6F0hcnNS4GH7q7mvlPUe/rpTlErmxxV1i78Swuvp24PEwtHS2U+ZSJcbxTHeD3Tj49c2KsGOVvNVjWweu/v0J4wA9CdSy/L1vFCiPKwHavyspnoOAfwS66x9KiGE9DDUTYqqHl078qIWqZkKQtTSKdwFdxtV02HNebcqI4XC+elT25kV8JaG2xjBcLbfUjmX+uF4Ywp0TBpwV9UE5tN3R8P3JzvhN63IoDhVPNqb0vEUWDVFvWoixzHZrbX4L/74e7YaLvjNvcIz6vOpF29+jJFzEsF3Qqmk/oZRXzd/Mt9l+qnExfPzWK+SOs2+b7gzr/92seSLeiWEVaCa8pWna/Um/u8GuPwzGU5J4UNuyKBtnlFPDueHPifXKAGVdHDKE+IwHnpeW0P69dDtGQ8CJQHf9g5sYTsTSLKovEb6JIDKlkxZ/WcFUYcfNOoesMGbG4lI9N5wKaT6TuM4kDJ3cGp8/dhSNx5V8Yjsl3snO8k/b6y6GJ6dltQUI07sZXxlCylPPZMKUZ2Jc3423kysQrHmh0rYw6amtbmlLrhhWQuzd3D/XU42L4UzpwjPEJ+Syli7UQgyzMzxXC+Hl7gkYzxppZ02sg7bSKVvFcIVJQvdUKEEOge4mu7gFAhDoO4Hu+gcXMWzZ0UwJNluUU0K+pjHNZVzVL6jUna8e2zPuTKfFb1aIutYmAzeTaLTYNDuKdbHsN4R4S7zTG1wutSMT7j0To2vJIn0ZwaqVybwzq4aUGxYjXO5VSaG01xG3ndn0zrV+OZrZhvSijpljcqla9UUR1xqjPteRGG7vQi3EMGK4SsPgnQEQUAebHdFt09kjAYjhAXiy9iJ2N9mt3RQShAAEaibQXf/gIIYdBegsBNp82dEsFHcOUeFYFlf3RGUuKo8DI0OGeedf11QRXiQaHSIq3XeG8y/91MPYo0gAt4UMvQz5oc0mD1UXw1k/6pELk/ysu9tBWZI6a7tAK4gALKonrrXO7bmGxXD0jeFHdt0ph68Prs+Kvzl8Pt8ZdnPPnE85NOo5c+jt690Ndr1FMr6CqSvl19xjEcOESY/P8cUW0f6LGfnwhNvZPB9IYKNKoLv+wUHoGXcUg9IbxIt+rlU5Vxram/kkYUmBUWeYdFggt/Dq4rPMen02nJ9OPTKzu/C2Yiv/WYLziOF0nxSXS9TFfDdGiW+jDYAq9564hTJnPrGkhZTPqBjKYLjM9+BJ8yVqyeeXwh3mi/YXfz2k5i6tYTEclDYWwM/GJT93dn64ZluMybEzzM5wG/WMPDog4BQ2xgVaHXim8yy7m+x2bjoFgAAECgh01z84iOGqu7FT4WH7LE4S1lpGENd7gVZjYjhPwBrPA+ecR21SDNuEZMrnjmJYXRx552ol8VjpAq2q9TNuk8WXoU6WfQq/HlJ/F9eCGK6/0GVSRAwjhsvUF57tIQHb4GT6bJL+vcLSz/TQfopUmkB3k93SReUFCECgZQLd9Q8OYti2e2rdkZvBq2PXM+0Ky+5h1VDjlA0i+xe3yaHMt4DdwoTVcubvJGshvDYxN7Xpdlm/KPtZKHUnNru7OSmNHhZsYmSZy+jnpHPP2ypznGSHenn3mqzlfm3D3MDydritF3E57gznnXtO0jbnX97/dXQfiOE6KPY1DcKk++oZylWKgNt5lOiCizWZXeRgu2Si4JlSZePhPhLobrLbRxqUCQIQUAl01z+4iOF4Z2zyOR77bdKm3UM17evkHoPQLB9+PKHmMq4aqlc2r2RnWtm5Ntww7XauOCWFw08jTi+uMpTFKDZTZ5dNt0Ub+CfCPSMIlTDt1AVa2plh02WgSijx1N+G53LPRE9sntWVMm09e2bXpY6UOTM8u8el+Ab0oOQu+Zex0PVZxLArqSE+hxgeotcos4WAftmEfnth+Jp+Rsr0bUKXZ/DCoAl0N9kdNDYKDwEvCHTXPxScbVXHq5zv3EZO0r9DO/lT6rZmU17pEGpn4VE0Zlp2CzNn9l3GY/3cc8E548LdcJWVwmee7wyHSWr+Wb7vlCy9f7LTnezc2nbPM+e4A5+syGpG0Nu/M5xaCggvJcuGxrtxCVLS64meljlsO+PbzHewHedjej02pdNCr4QYbgEyWbRPoLvBrn1byRECEEgToP1TIyAAARsB+oeB1Y1AQN58sZwu+ozTwMyav7jdhBTPX+7+pYAY7p9PKFENBBjsaoBIEhAYKAHa/0AdR7Eh0AIB+ocWINeYRbALuUeOyekDSzWmOoKkwl3mo7L35Gk5uH0E9nRoAmK4Q/hk3RwBBrvm2JIyBPpOgPbfdw9RPgh0R4D+oTv25XMOdj/3y8UbxyTzmZ/yiY3jDdM543FY1pkViOHO0JNxkwQY7JqkS9oQ6DcB2n+//UPpINAlAfqHLumTNwT6RwAx3D+fUKIaCDDY1QCRJCAwUAK0/4E6jmJDoAUC9A8tQCYLCAyIAGJ4QM6iqO4EGOzcWfEkBMZGgPY/No9iDwTqI0D/UB9LUoLAGAgsPPLoic0xGJJnw2Wv3zV2E7EPAhCAAAQgAAEIQAACEIAABEoQYGe4BCweHQ4BVn6H4ytKCoG6CdD+6yZKehAYDwH6h/H4EksgUAcBxHAdFEmjdwQY7HrnEgoEgdYI0P5bQ01GEBgcAfqHwbmMAkOgUQKI4UbxknhXBBjsuiJPvhDongDtv3sfUAII9JUA/UNfPUO5INANAcRwN9zJtWECDHYNAyZ5CPSYAO2/x86haBDomAD9Q8cOIHsI9IwAYrhnDqE49RBgsKuHI6lAYIgEaP9D9BplhkA7BOgf2uFMLhAYCgHE8FA8RTlLEWCwK4WLhyEwKgK0/1G5E2MgUCsB+odacZIYBAZPoB0x/NCtcvkdX4xhXSI3Pnib7G4J3YnHviC7dl7aUm5k0xcCDHZ98QTlgED7BGj/7TMnRwgMhQD9w1A8RTkh0A6B5sXw03fL1Td8XM6/8bPywTeJPHX3tfKeE7vkI/deLxe2YCNiuAXIPcyCwa6HTqFIEGiJAO2/JdB9yubJ/bL1okOyoZdpyz45tXFQlpK/68/tXpXNtav6ZAllaZhAU/3DkeUFWTm+LKubx2RINSoqdwJ9UfadPC0Htxc4QW9HejuLXy+b9vrNW2Xbh5bmY3h4jyxcszYpgaMtDde33ic/5RWVdPGmU3L6wLTHtBY/8tWsx12+b1OOXW17/IjsWVgRsT6T9/u67F/cJofOzNLOz6s88cbFcCh+n3mnfO62K8uXroY3EMM1QBxgEk0NdgNEQZEh4B0B2r93LhcJJ3Tr+RP5eAK/NJ2QRROwNQSxVxWmqf5hiGI4LPP6bMEoEjji1I5kKpoSsZJeCCid9lRgz7egEOW7KItnNmSDtp3ftvV+M/bBzLfm16O6riw25L43E7NmEZv3e9xHK4stiQivUxA3LIafkruuvUEe2XWnHL6+jX3grNMQw16NcVNjmxrs/KSJ1RAYFgHa/7D8VUdpwwnS/XvTu8CphOMJl2g7xS4iuo4CkkZvCDTVPwxODMc7gmlREbeTJXvEhC5yQ8fqC02l01Z3/+YRw5F4Wp8I9duf3DbInfr2Gop5MbBwd94ifI3vaREEGQFb8Lu5LMV1tCzDVsTw2ZX3itzxYYlODXNmuKyTeL48gaYGu/Il4Q0IQKBtArT/tol3n184QZe8kOfZJDkdAmj7e/c2UYJmCDTVP7iL4ViETM3LhvOmw4snDxaF+08eSQkNhx0+m+gpFEMmt2hiuGzayWLW6juOyooWJu20Wx2XKfWsREcnZpEgasF1H2QFuB4GPAsftogxbQEgsWnf0iE5FIahz/yc8a8YFgC08GVJdrltvk35wCHqJRMpE/Ox/T3BZ1tA1N9LhG5Q7gOPZ31R9LtEnI++wy1se57eohUx/MCzMwF8/NYr5I6zb+PM8Dxe491CAk0NdoUZ8wAEINA5Adp/5y5ouQCxoN2yKBuT0MjpPzVE0jrBc5g0tmwN2TVLoKn+wUkMqwIgPquuh31m09HEl0kMVYhwMO7wTtCXEZ+Rp7KhrKXSVsp+3X3znBnWoz8s0SAGH+jM88OAJTrDqu+em8RwcKZWC9XOssmWMxsKrPZTO6L8tSiX0osYBaLWGipd5b0igW38fXaO+OBJ9Xxy/WfBWxHDqTDp8EKtE3LZnffKuy9otsMLUidMunnGfcyhqcGuj7ZSJghAIE2A9u9ZjTBMbjMTdOtkrP6QO8/oD87cpvoHFzFsFomqGLpO7jEJLZVyBeFrcpJNsDqdvw8TVEOb0wLFPe10ZEZpQacaZmjjJmFvLptygdMO847y7CiGxUdGMaydv7b1QymfWqJVwmckvFxsR+Zsd4V+zFqPCqJlcm1YM1/AVUUMqyHUyoLCAM8MiwQ7wUfOU84Mh2L4Gbmqpc8rIYYHN07VUuCmBrtaCkciEIBAowRo/43iHU7i6uTUMsGdTuhzzkgOx2BK6kKgqf6hWAzbBYsqAiOhE0Q42HbAlBDfOS6IchesDlTjtpaEErumbb5kq9pt0kb+mYUyB9FYuNhQIkw692Zs/Zbk2N+54d2JLzTBWiQ2TS6sKoYnadl2zsNaa7qNuqh8pt8T32VuKrfs+DtUU9sjDe8MT7INvzEs028Lh2HS8t7WbpdGDM9ROwb8alOD3YCRUHQIeEOA9u+Nq/MNVcNJr7nHcn6QMGnfaktT/UOxGLbXtcyOqHaxkEkYZ86dlhTGpUKZHSqJar9ot1Qnr6d2ap/I3gBffWdYPwOsFzg5k1vc3ovDxOcTw2m/xeVShWnIZS19BtzAX/WfVPkkVZVwZ6UcKTtCwXqx7I8vL8t8mmkeMWyo19XribkiNy+Gg3xDQRxdnyXntndeOMgOMezQg43wkaYGuxGiwiQIjI4A7X90Lq1mUOps5RPTW2a5QKsazrG81VT/UCyG3XaGs98oToSe/azk9LKnEoK47CVXRf5X7Y92t7M7vGqeoWCeft84m7rr926DN3MFbCp8uWMxbLxle2JABTE8e+eYyFsMZ5iLHFb1Ai1bumF6R2Wv6TvVVcRwchZ9NGK4yCEN/o4YbhBuj5NuarDrsckUDQIQiAnQ/j2rCi4TzO15uzkF3yf2DOfYzW2qfygWw0l4qX5zsEPYp62OT53lkIbuWOPOYFEYse13Lf9KaSeitmyYdJHt6Qu+njDuWit2mW4+DthNbTKLT/0sq2mxwSba02HHljO7GUEZP7d7eXImdd0sQnMbszmfwl1Xi7DNfa+SGC5oLzUebWlnZ7jDnhUx3CH8DrNuarDr0CSyhgAEHAnQ/h1Bjeax5OydIjJMl2pp5xqnl2yV2E0bDTKPDWmqf3ARw8n3eDesFwKZhV0qbZMwNt0wXejjbLspDhFORGE6jDcJmZ193qla2oVCzGSTg+0psRmfyc36YHbZVeZMrLZLmeGkhLUnDIy2ZPqgGU81FD57SZS5XkwjAjLnagudHz6QyceBZfBeJsS+aLGmohi2txftYjI3c61PIYbnBMjr/STQ1GDXT2spFQQgoBKg/ftZH/QzlHkXuUw/wIQQ9q6yNNU/ZM7wqmRTYqXoG7f6xUpBQtpusv4N2skTqfruKGqmwmYarmz75rGWf+ZMs+E7uYloyklbr3xldlOTd6stQhT5YCYUk3z0/iRz9vfkktyifNfYKux13wV149Mieybvpj5nZPvOsArN6uficPBpMlo+up35u9lTOrLPFB6d/FxVDIfvF3+Xe95ODDE8L0He7yWBpga7XhpLoSAAgRQB2j8VAgIQsBGgfxhe3TiyvFUeP3BaDm4fXtkbLXHhzdeN5j6axBHDo3ElhqgEGOyoDxDwlwDt31/fYzkEigjQPxQR6tvvwc7gqqxMvq+bvVysb2Vttzzh7rSsyuYaZOYhjxiehx7v9pYAg11vXUPBINA4Adp/44jJAAKDJUD/MDDXTXY/t548KJnP9QzMjDqLOw3RrnhWuM6yjCEtxPAYvIgNGQIMdlQKCPhLgPbvr++xHAJFBOgfigjxOwT8IoAY9svf3ljLYOeNqzEUAiyGUQcgAAFnAswPnFHxIAS8IIAY9sLN/hnJYOefz7EYAgkB2j91AQIQsBGgf6BuQAACKoGFRx49sTl2JLt2Xjp2E7FPI8BgR5WAgL8EgvbPPwhAAAIQgAAEIFBEgJ3hIkL8PkgCiOFBuo1CQ6AWArT/WjCSCARGSYD+YZRuxSgIVCaAGK6Mjhf7TIDBrs/eoWwQaJYA7b9ZvqQOgSEToH8YsvcoOwTqJ4AYrp8pKfaAAINdD5xAESDQEQHaf0fgyRYCAyBA/zAAJ1FECLRIADHcImyyao8Ag117rMkJAn0jQPvvm0coDwT6Q4D+oT++oCQQ6AMBxHAfvEAZaifAYFc7UhKEwGAI0P4H4yoKCoHWCdA/tI6cDCHQawKI4V67h8JVJcBgV5Uc70Fg+ARo/8P3IRZAoCkC9A9NkSVdCAyTQMNi+Cm569ob5IFndTivlLffea+8+4LmoZ147AvCp5Wa59y3HBjs+uYRygOB9gjQ/ttjTU4QGBoB+oeheYzyQqBZAg2L4Wzhj996hdwh75XP3XZls5bFqfsoho8sL8jKcQXv7lXZXLuqFd59yYTBri+eqK8cer1evm9Tjl2tpf/kftl60SHZSP5sqvsuz9RXbFLqgADtvwPonWV5RPYsrIiY+gNZl/2L2+TQmaRwy7K6eUz00TDdtyzKvpOn5eD2zgwi44YJdNc/xPVR9smpjYOy1LCdtSVfccxcv3mrbPvQdDSWxZtOyekDaasz89W40Mbx3cUgpayV03DJZzTPuPWRGXMP75GFa9amfzb5Vhz73ySRsL7cv7eTttGuGH7oVrn8DpEbH7xNdrdUkfwSw0mlVgf8aKKwtmVgne+c9aO7wW7OgvO6kUA0YCr1Ou6IUx1wPAguTSfFcd1XBbHLM/hg8ARo/4N3oaMBs4lcduIb/7Y0WwzO9COTXMK/rc/Gx2gCLwhiRw8M8bHu+ocBiuGKY2amHSUiNbVAnW2j89anJN/FLRuTRXG/5r3l2bn1kXq6ySLHrM81zLUSIVzQ/07TTsR1R1qlRTEchUw/sutOOXz9heV9VvENr8RwptOKoYWVbN2rwb27wa5iReU1OwFLvU5PYi2TjFTdd3kGR4yBAO1/DF4ssEHbrdLFsFnURpO29WSHKp6Apd+tf4LugTcGZWJ3/cPQxHDVMVNrZ3HtiNrkkhKdkRfVUaVKzdruqe23sKhVgNCpj8ykYRK+k4c0nVEm7VR0wOjFcAe7woEPvRLDtopvHPCrdDTDeae7wW44jIZe0rQYNg++k30fZfL7RHoiPAVge3fohPwtP+1/5L5Xd5kOPB4ejZhFhES26zu+CRH175KZnEdPZSftI+fpmXnd9Q8lxLAWhioZkaCHt06cqB0LyoQga2mYIiXSVcFlXHUP9s60q7AdH5W9uccSLOLLVGdTc938cb0whFvnr7A19w9aOcP3JxEmN63LoThUPFl00/MWMR3NiNOb2jmLjLP5Ldu35Ue4uPSRGe/aNt1Sc60lp/43SDuyJbL/4pvTUTptdkut7Qy3fVY4gYgYTgZ2v8K+uhvs2my+/uaVCdMp6KDXgoHMMmlOBHP4jGdn68dag2j/Y/WswS5j27fv7qoTSdFCpJPUCZUed/3prn9wE8PZMFT9CJwpnbT4ywqmChEPLuOq65hpONqUCmk+k9S56mf2dZtzRWMswMK7AWI7JY4YKQoDdhfDkzO12gKE6d1MOQ0h5alnjBtcZRf13frIzG1DTnViR3RXgxIinVqMVI+8KV2NTZy30Ru1JIajEOmzK5+VD76pDbNmeXgvho3nNNr1QRe5dTfYdWGtR3mqq7W5Z4Gn09pZp2wVwxUmCR4hH6KptP8heq1imUuKYXUyahPDeshfxZLxWk8JdNc/uIhhi6hJCTZblJNh3HMVqyZfWYVPiTFTPc5g3JlOi9+sEHWtRAZuJtFosWl2edPFsl89SpFkH+/0Bhfw7TBGlJh2htckfQQj37dJdItZFKoh5Ybd8tLHIe0+zI+MybdhI5yX2cVwXtrjF8NP3y1X33BCLmvpc0pq0/FbDCdhFuYbNF27mCE+191gN0RaQyyztlLuMmgjhofo6Eplpv1XwjbMlxDDw/Rbh6Xurn9wEMMuY9lE4M5CoM3zu1kobvWd1mTHVD+CML0l2LDzl+dWNSTWflu7AyNDJnlnVFMXyBaJRiv/WabuO8P5d/WYv5DhttCgl6G8kKwqhpNo0w1F6Csh3YjhnCYQnBdePU8+cu/10t7VWVF5/BXD/grhwO/dDXYdjvC+Za2ulF9zj/HcYCoEmjBpb2oI7d8bV09DHNMTdrcQQMKkPaoniqnd9Q8OQs96x4uhTuvnWkUTxvonkYxnU3PqgFNIbJnPdrqd/y0+y6yX2XB+OvXIbEGg8AiEwx0784jh9HnhuFwSfRIy6sPcGKUXKsqGSAdw3PpIm3fTdgT17qA8Pg2NJkza2Kqeuvtaec+JXYjhtsadaQfo345wgri7wa4tJ5NP+pyPy+VYLs+4XwaCB/pLgPbfX9/UXjKn2+ZnuXKBVu0eGFyC3fUPDmLYcWc4A71w3pdskJTZKa73Ai3X+zlKi+E8AWs8D5xzh06TYlgry9SHKZ87imFVzL5ztdIXYypdoGVt7embwaukXX53u76up6Uzw/UVuGxK3u0MJx1iR9eTl/VPU893N9g1ZZHH6drCmlKDlmWV0/RpJT20qyhsymP0QzWd9j9Uz1Uod94ZwNRnXIK0TZ9W0kMZ3cIUK5SUV3pCoLv+wUEMx3U0c6GjTUgpTOvY9Uy7yGVcNTjVJuhTNkh0n0fmW8Dl21++eHY8UjWdB9wu6xcpn19LzFNsOnhS/0TU5CH9fh7TvMIitPVz0mZRmOWS7FAv716TNSl/AWjeDvf083MZ91oWSIyfVlI/o2Xof7W0EcMNdpB+ieF4RclzIRxUp+4GuwYrs7dJGyYQpkWfzG2Vtksm1mQx+c6obeLhLetxGE77H4cfnawoCuVUxkPrDbtnZlFUhYLCqVA81GcC3fUPLmLYdCZTv03atHuopn2d3GMQmqV3XAMnuoyrBmdn8zIc3TPcMO12rljNsHgn1Sg21duktXmA9TbvRLhnFiaUMO3kYk+TGDZdaKuEsk8v2zI8l3smeoJD/866W/vLagaXOmL+RNYhSW7jjvIunzZi2M1rlZ7ySQxnv12WRjYTAJVQDuql7ga7QWEaVGH1yyaM9Vk/I2X6XJLLM4MiQ2F1ArR/j+pE7oU3+llC89GhdN9SJozUI84jMrW7/qHgbKs6XuV85zYlNlS/pDZCTHml67+L8AmTLxozLbvWmTmpy3isn3suWLB2W7zKCjO9bJn5RBF/7ffl+07J0vuVzwnZIs4y57gDn6zI6uQG63Q0gP07w6mlgPA7vdl+zY1LkFJRH2lebND5mcV4UdrpTgUx3GAn65MYbhDj4JLubrAbHCoKDIHREaD9j86lGASB2gjQP9SGsp2EAgF588Vyep7PRLVT0pZzKR9S3nIBB5MdZ4YH4yoKWoYAg10ZWjwLgXERoP2Py59YA4E6CdA/1Emz+bSCXcg9ckxOH+CCyxTtcJf5qOw9eVrsn6pq3j9jyAExPAYvYkOGAIMdlQIC/hKg/fvreyyHQBEB+ociQn36Pdj93C8XbxyTMh9x6pMFtZfFdM649kz8ShAx7Je/vbGWwc4bV2MoBFgMow5AAALOBJgfOKPiQQh4QQAx7IWb/TOSwc4/n2MxBBICtH/qAgQgYCNA/0DdgAAEVAKIYerDKAkw2I3SrRgFAScCtH8nTDwEAS8J0D946XaMhoCVwMIjj57YHDufy16/a+wmYh8EIAABCEAAAhCAAAQgAAEIlCDAznAJWDw6HAJnz56V888/fzgFpqQQgEBtBGj/taEkIQiMjgD9w+hcikEQmIsAYngufLzcVwIMdn31DOWCQPMEaP/NMyYHCAyVAP3DUD1HuSHQDIEXiQfEAAAABklEQVT/H9MAxdg85t3FAAAAAElFTkSuQmCC)"],"metadata":{"id":"3rA05vGIDC4H"}},{"cell_type":"markdown","source":["11) Сохранить наилучшую нейронную сеть на диск. Данную нейронную сеть потребуется загрузить с диска в одной из следующих лабораторных работ."],"metadata":{"id":"mUcd8nnoLjXe"}},{"cell_type":"code","source":["model_100.save(\"/content/drive/MyDrive/Colab Notebooks/best_model_100.keras\")"],"metadata":{"id":"HS3dgfuKLocO"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["12) Для нейронной сети наилучшей архитектурывывести два тестовых изображения, истинные метки и результат распознавания изображений."],"metadata":{"id":"iWjIiC3oNUZe"}},{"cell_type":"code","source":["n = 333\n","result = model_100.predict(X_test[n:n+1])\n","print('NNoutput:',result)\n","plt.imshow(X_test[n].reshape(28,28),cmap=plt.get_cmap('gray'))\n","plt.show()\n","print('Realmark:',str(np.argmax(y_test[n])))\n","print('NNanswer:',str(np.argmax(result)))"],"metadata":{"id":"h6EsX0sWNV1Y"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["n = 234\n","result = model_100.predict(X_test[n:n+1])\n","print('NNoutput:',result)\n","plt.imshow(X_test[n].reshape(28,28),cmap=plt.get_cmap('gray'))\n","plt.show()\n","print('Realmark:',str(np.argmax(y_test[n])))\n","print('NNanswer:',str(np.argmax(result)))"],"metadata":{"id":"fA6xMRS7Ny_U"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["13\n"],"metadata":{"id":"FzvS0hqHefWX"}},{"cell_type":"code","source":["from keras.models import load_model\n","\n","model_100=load_model('/content/drive/MyDrive/Colab Notebooks/best_model_100.keras')"],"metadata":{"id":"N-z0ErgfkHdv"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["\n","file_data=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_7.png')\n","file_data=file_data.convert('L')\n","test_img=np.array(file_data)\n"],"metadata":{"id":"uQXfnnNEcF46"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["#выводсобственногоизображения\n","plt.imshow(test_img,cmap=plt.get_cmap('gray'))\n","plt.show()\n","#предобработка\n","test_img=test_img/255\n","test_img=test_img.reshape(1,num_pixels)\n","#распознавание\n","result=model_100.predict(test_img)\n","print('I think it\\'s',np.argmax(result))"],"metadata":{"id":"RDl8sPM_vnXn"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["\n","file_data_4=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_4.png')\n","file_data_4=file_data_4.convert('L')\n","test_img_4=np.array(file_data_4)"],"metadata":{"id":"M8XBxYIDv1Ui"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["#выводсобственногоизображения\n","plt.imshow(test_img_4,cmap=plt.get_cmap('gray'))\n","plt.show()\n","#предобработка\n","test_img_4=test_img_4/255\n","test_img_4=test_img_4.reshape(1,num_pixels)\n","#распознавание\n","result=model_100.predict(test_img_4)\n","print('I think it\\'s',np.argmax(result))"],"metadata":{"id":"iBTfB4W8v5Pi"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["14. Каждому члену бригады создать копию собственного изображения, отличающуюся от оригинала поворотом на 90 градусов в любую сторону. Сохранить изображения. Загрузить, предобработать и подать на вход обученной нейронной сети измененные изображения. Вывести изображения и результаты распознавания. Сделать выводы по результатам эксперимента."],"metadata":{"id":"-HMUj57ZR1N8"}},{"cell_type":"code","source":["from PIL import Image\n","file_data=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_7_90.png')\n","file_data=file_data.convert('L')\n","test_img=np.array(file_data)\n"],"metadata":{"id":"AGQgEWl1PLIv"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["#выводсобственногоизображения\n","plt.imshow(test_img,cmap=plt.get_cmap('gray'))\n","plt.show()\n","#предобработка\n","test_img=test_img/255\n","test_img=test_img.reshape(1,num_pixels)\n","#распознавание\n","result=model_100.predict(test_img)\n","print('Ithinkit\\'s',np.argmax(result))"],"metadata":{"id":"NkaPb4jtRktK"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["from PIL import Image\n","file_data_4=Image.open('/content/drive/MyDrive/Colab Notebooks/IS_lab_4_90.png')\n","file_data_4=file_data_4.convert('L')\n","test_img_4=np.array(file_data_4)\n"],"metadata":{"id":"osOpZLGtU4Sd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["#выводсобственногоизображения\n","plt.imshow(test_img_4,cmap=plt.get_cmap('gray'))\n","plt.show()\n","#предобработка\n","test_img_4=test_img_4/255\n","test_img_4=test_img_4.reshape(1,num_pixels)\n","#распознавание\n","result=model_100.predict(test_img_4)\n","print('Ithinkit\\'s',np.argmax(result))"],"metadata":{"id":"hR_dW-lLU_Ga"},"execution_count":null,"outputs":[]}]} \ No newline at end of file