gorschal
gorschal
I'm i.Gorschal
6 posts
Don't wanna be here? Send us removal request.
gorschal · 6 years ago
Video
youtube
0 notes
gorschal · 6 years ago
Text
Как стартануть контейнер X после того как стартанет Y
Небольшой лафхак. Стандартная ситуация состоящая из приложения и базы данных где хранятся наши данные. В виде docker-compose файла это выглядит примерно так:
version: "3" services: cassandra: image: cassandra:3.11 container_name: cassandra restart: always volumes: - cassandra-metrix-data:/var/lib/cassandra ports: - 7000:7000 - 7001:7001 - 7199:7199 - 9042:9042 - 9160:9160 agent: build: context: . dockerfile: ./Dockerfile target: develop container_name: agent depends_on: - cassandra
Но есть одна небольшая проблема. Наше приложение agent зависит от данных и скорее всего запустится быстрее чем cassandra. Результат предсказуем: не найдя источник данных наш agent сфейлится.
Чтобы этого не произошло можно в агент добавить нечто подобное:
restart: on-failure
Что позволяет перезапускать агента в случае падения. И теоретически он так будет запускаться пока cassandra не поднимется.
Но можно поступить красивее. Добавляем в .Dockerfile агента следующую запись:
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.1/wait ${PROJECTPATH}/wait RUN chmod +x ${PROJECTPATH}/wait
Теперь наш docker-compose файл примет следующий вид:
agent: build: context: . dockerfile: ./Dockerfile target: develop container_name: agent environment: WAIT_HOSTS: cassandra:9160, cassandra:9042 command: python agent.py volumes: - .:/opt/metrix-agent/app ports: - 8095:8095 - 8094:8094 tty: true restart: on-failure depends_on: - cassandra
Поясню. Теперь наш agent прежде чем выполнить команду python agent.py будет ждать пока наша cassandra не будет доступна на соответствующих портах. В нашем случае это:
environment: WAIT_HOSTS: cassandra:9160, cassandra:9042
Данный лайфхак доступен для любого случая кода вам необходимо стартануть контейнер X после того как стартанет Y. Не забывайте только подставлять правильные имена контейнеро�� и порты которые необходимо контролировать.
0 notes
gorschal · 6 years ago
Text
Python на колесах
Wheels в питоне настолько старая фича что про нее все забыли примерно в 2005 году. Так что это такое и почему я про это решил напомнить вам.
Основной формат распространения приложений в питоне это исходные файлы. Тем не менее существуют и бинарные форматы. Например egg. Python eggs это обычные zip-архивы, содержащие python-пакет и необходимые метаданные. Это не было идеальным решение и в один прекрасный момент на смену ему пришел Python wheels. Который попытался решить основные проблемы присущие egg. Понятно что все решить не смог и кое что пришлось унаследовать от предшественника. К примеру бинарные 'колёса' нельзя загружать на PyPI как несовместимые с различными системами. Или проще говоря бинарные wheel’ы по сути можно использовать только в своих собственных однородных инфраструктурах. Ключевое слово однородных. А как мы знаем даже в рамках одной команды однородности мало.
Казалось бы все печально, но не так как могло показаться. Мы живем в эпоху докеров а докеры это как раз та самая однородная среда. А это значит что если мы используем docker’ы в своем девелопмент процессах то мы можем и wheel’ы использовать в полном объеме. А это в первую очередь поможет нам ускорить сборку приложений и в некоторых случаях даже более чем в сотни раз.
Создаем архив wheel пакетов
И так у нас есть типичный Python проект с файлом requirements.txt содержащим зависимости.
# Core cassandra-driver==3.17.0 aiohttp==3.5.4 # Supplement cchardet==2.1.4 aiodns==2.0.0 uvloop==0.12.2
Для начала нам необходимо установить пакеты. Действуем обычным способом:
$ pip install -r requirements.txt
Теперь нам необходимо сгенерировать архив wheel для всех наших пакетов и их зависимостей. И сложить их куда нибудь нам в проект.
$ mkdir wheels $ pip wheel -w wheels/ -r requirements.txt
Теперь когда в директории wheels есть все необходимые пакеты для установки всех зависимостей системы можем просто выполнить:
$ pip install --no-index -f wheels/ -r requirements.txt
В результате время установки пакетов из локального архива ускорилось на порядки.
0 notes
gorschal · 6 years ago
Text
Что нового в TensorFlow 2.0
TensorFlow как никто другой оказывает влияние на machine learning комьюнити. Фреймворк с недавних пор уже в бете с литерой 2.0. Это достаточно серьезный апдейт и в этом тексте хочу осветить наиболее значимые моменты.
Это не руководство по AI и для понимания вы уже должны быть знакомы с TensorFlow.
Установка и демонстрационный набор данных
Используем Jupyter Notebook:
$ pip install tensorflow==2.0.0-beta1
Если необходимо использовать графический процессор (CUDA):
$ pip install tensorflow-gpu==2.0.0-beta1
Нам также будет необходим тестовый набор данных. Будем использовать набор данных Adult из архива UCI.
import pandas as pd columns = ["Age", "WorkClass", "fnlwgt", "Education", "EducationNum", "MaritalStatus", "Occupation", "Relationship", "Race", "Gender", "CapitalGain", "CapitalLoss", "HoursPerWeek", "NativeCountry", "Income"] data = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data', header=None, names=columns) data.head()
Набор данных представляет собой задачу двоичной классификации, которая заключается в прогнозировании, будет ли человек зарабатывать более 50 000 долларов в год.
Для начала проведем базовую предварительную обработку данных, а затем настроим разделение данных в соотношении 80:20:
from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split import numpy as np # Label Encode le = LabelEncoder() data = data.apply(le.fit_transform) # Segregate data features & convert into NumPy arrays X = data.iloc[:, 0:-1].values y = data['Income'].values # Split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=7)
Если TensorFlow у нас установился, датасет загрузился, то можно переходить к самому интересному.
1. Eager execution по умолчанию
В TensorFlow 2.0 больше не нужно создавать сессию и запускать в нем граф вычислений. Eager execution включено по умолчанию в версии 2.0, так что вы можете создавать модели и запускать их мгновенно. Отключить eager execution можно следующим образом:
tf.compat.v1.disable_eager_execution() (provided tensorflow is imported with tf alias.)
2. tf.function и AutoGraph
В то время как eager execution позволяет вам работать с императивным программированием, но как только речь заходит о распределенном обучении, полномасштабной оптимизации, производственные среды style graph execution TensorFlow 1.x имеет свои преимущества по сравнению с eager execution. В TensorFlow 2.0 вы сохраняете выполнение на основе графов, но более гибким способом. Это можно сделать с помощью tf.function и AutoGraph.
tf.function позволяет определять графы TensorFlow с синтаксисом в стиле Python с помощью функции AutoGraph. AutoGraph поддерживает широкий диапазон совместимости с Python, включая оператор if, цикл for, цикл while, итераторы и т. д. Однако существуют ограничения. Здесь вы можете ознакомиться с полным списком доступных на данный момент операторов. Ниже приведен пример, показывающий, как легко определить граф TensorFlow с помощью простого декоратора.
import tensorflow as tf # Define the forward pass @tf.function def single_layer(x, y): return tf.nn.relu(tf.matmul(x, y)) # Generate random data drawn from a uniform distribution x = tf.random.uniform((2, 3)) y = tf.random.uniform((3, 5)) single_layer(x, y)
Обратите внимание, что вам не нужно было создавать сессии или поля для заполнения для запуска функции single_layer (). Это одна из замечательных функций tf.function. Из-за этого он выполняет все необходимые оптимизации, чтобы код работал быстрее.
3. tf.variable_scope больше не нужен
В версии TensorFlow 1.x, для того, чтобы использовать tf.layers в качестве переменных и использовать их повторно, Вам нужно был использовать блок tf.variable. Но этого больше не нужно делать в TensorFlow 2.0. Из-за присутствия keras в качестве центрального высокоуровневого API в TensorFlow 2.0 все слои, созданные с использованием tf.layers, могут быть легко помещены в определение tf.keras.Sequential. Это значительно облегчает чтение кода, а также позволяет отслеживать переменные и потери.
Пример:
# Define the model model = tf.keras.Sequential([ tf.keras.layers.Dropout(rate=0.2, input_shape=X_train.shape[1:]), tf.keras.layers.Dense(units=64, activation='relu'), tf.keras.layers.Dropout(rate=0.2), tf.keras.layers.Dense(units=64, activation='relu'), tf.keras.layers.Dropout(rate=0.2), tf.keras.layers.Dense(units=1, activation='sigmoid') ]) # Get the output probabilities out_probs = model(X_train.astype(np.float32), training=True) print(out_probs)
В приведенном выше примере вы передали набор данных для обучения через model просто для получения необработанных выходных вероятностей. Обратите внимание, что это просто прямой проход. Вы можете, конечно, пойти вперед и обучать свою модель:
model.compile(loss='binary_crossentropy', optimizer='adam') model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=5, batch_size=64)
Вы можете получить список обучаемых параметров модели по слоям, например:
# Model's trainable parameters in a layer by layer fashion model.trainable_variables
4. Кастомные слои это просто
В исследованиях в области машинного обучения и в промышленных приложениях часто возникает необходимость в написании кастомных слоев для удовлетворения конкретных случаев использования. TensorFlow 2.0 позволяет очень просто написать собственный слой и использовать его вместе с существующими слоями. Вы также можете настроить прямой проход вашей модели любым удобным для вас способом.
Чтобы создать кастомный слой, проще всего расширить класс Layer из tf.keras.layers, а затем определить его соответствующим образом. Вы создадите кастомный слой, а затем определите его прямые вычисления.
Можно создать несколько слоев, расширяя класс Model из tf.keras. Подробнее о создании моделей можно узнать здесь.
5. Гибкость в обучении модели
TensorFlow может использовать автоматическое дифференцирование для вычисления градиентов функции потерь относительно параметров модели. tf.GradientTape создает ленту в контексте, который используется TensorFlow для отслеживания градиентов, записанных при каждом вычислении на этой ленте. Чтобы понять это, давайте определим модель на более низком уровне, расширив класс tf.keras.Model.
from tensorflow.keras import Model class CustomModel(Model): def __init__(self): super(CustomModel, self).__init__() self.do1 = tf.keras.layers.Dropout(rate=0.2, input_shape=(14,)) self.fc1 = tf.keras.layers.Dense(units=64, activation='relu') self.do2 = tf.keras.layers.Dropout(rate=0.2) self.fc2 = tf.keras.layers.Dense(units=64, activation='relu') self.do3 = tf.keras.layers.Dropout(rate=0.2) self.out = tf.keras.layers.Dense(units=1, activation='sigmoid') def call(self, x): x = self.do1(x) x = self.fc1(x) x = self.do2(x) x = self.fc2(x) x = self.do3(x) return self.out(x) model = CustomModel()
Обратите внимание, что топология этой модели точно такая же, как и та, которую вы определили ранее. Чтобы обучить эту модель с использованием автоматического дифференцирования, вам нужно по-разному определить функцию потерь и оптимайзер:
loss_func = tf.keras.losses.BinaryCrossentropy() optimizer = tf.keras.optimizers.Adam()
Теперь вы определите метрики, которые будут использоваться для измерения производительности сети, включающей ее обучение. Под производительностью здесь подразумеваются потеря и точность модели.
# Average the loss across the batch size within an epoch train_loss = tf.keras.metrics.Mean(name='train_loss') train_acc = tf.keras.metrics.BinaryAccuracy(name='train_acc') valid_loss = tf.keras.metrics.Mean(name='test_loss') valid_acc = tf.keras.metrics.BinaryAccuracy(name='valid_acc')
tf.data предоставляет служебные методы для определения конвейеров входных данных. Это особенно полезно, когда вы имеете дело с большим объемом данных.
Теперь вы определите генератор данных, который будет генерировать пакеты данных во время обучения модели.
X_train, X_test = X_train.astype(np.float32), X_test.astype(np.float32) y_train, y_test = y_train.astype(np.int64), y_test.astype(np.int64) y_train, y_test = y_train.reshape(-1, 1), y_test.reshape(-1, 1) # Batches of 64 train_ds = tf.data.Dataset.from_tensor_slices((X_train, y_train)).batch(64) test_ds = tf.data.Dataset.from_tensor_slices((X_test, y_test)).batch(64)
Теперь вы готовы обучать модель, используя tf.GradientTape. Во-первых, вы определите метод, который будет тренировать модель с данными, которые вы только что определили, используя tf.data.DataSet. Вы также оберните этапы обучения модели с помощью декоратора tf.function, чтобы ускорить вычисления.
6. Наборы данных TensorFlow
Отдельный модуль DataSets используется для отточенной работы с сетевой моделью. Вы уже видели это в предыдущем примере. В этом разделе вы увидите, как можно загрузить набор данных MNIST именно так, как вам нужно.
Вы можете установить библиотеку tenorflow_datasets с помощью pip. Как только он установлен, вы готовы приступать к работе. Он предоставляет несколько вспомогательных функций, которые помогут вам гибко подготовить конвейер построения ��абора данных. Вы можете узнать больше об этих функциях здесь и здесь. Теперь вы увидите, как вы можете построить конвейер ввода данных для загрузки в наборе данных MNIST.
import tensorflow_datasets as tfds # You can fetch the DatasetBuilder class by string mnist_builder = tfds.builder("mnist") # Download the dataset mnist_builder.download_and_prepare() # Construct a tf.data.Dataset: train and test ds_train, ds_test = mnist_builder.as_dataset(split=[tfds.Split.TRAIN, tfds.Split.TEST])
Вы можете игнорировать предупреждение. Обратите внимание, как оригинально tennsflow_datasets обрабатывает конвейер.
# Prepare batches of 128 from the training set ds_train = ds_train.batch(128) # Load in the dataset in the simplest way possible for features in ds_train: image, label = features["image"], features["label"]
Теперь вы можете отобразить первое изображение из коллекции изображений, в которую вы загрузили. Обратите внимание, что tennsflow_datasets работает в активном режиме и настроен на основе графа.
import matplotlib.pyplot as plt %matplotlib inline # You can convert a TensorFlow tensor just by using # .numpy() plt.imshow(image[0].numpy().reshape(28, 28), cmap=plt.cm.binary) plt.show()
7. Политика автоматической смешанной точности
Политика смешанной точности была предложена NVIDIA в прошлом году. Оригинал статьи находится здесь. Кратко об основной идеи политики смешанной точности: использовать смесь половин (FP16) и полной точности (FP32) и использовать преимущества обоих миров. Она показала потрясающие результаты в обучении очень глубоких нейронных сетей (как с точки зрения времени и оценки).
Если вы работаете в среде графического процессора с поддержкой CUDA (например, Volta Generation, Tesla T4) и установили вариант TensorFlow 2.0 с графическим процессором, вы можете дать TensorFlow команду обучаться со смешанной точностью, например, так:
os.environ['TF_ENABLE_AUTO_MIXED_PRECISION'] = '1'
Это автоматически распределит операции графа TensorFlow соответственно. Вы сможете увидеть хороший скачок производительности вашей модели. Вы также можете оптимизировать основные операции TensorFlow с помощью политики смешанной точности. Подробнее почитайте в этой статье.
8. Распределенное обучение
TensorFlow 2.0 позволяет очень легко распределять процесс обучения по нескольким графическим процессорам. Это особенно полезно для производственных целей, когда вам приходится встречать сверхтяжелые нагрузки. Это так же просто, как поместить ваш тренировочный блок в блок with.
Сначала вы указываете стратегию распределения следующим образом:
mirrored_strategy = tf.distribute.MirroredStrategy()
Зеркальная стратегия создает одну реплику для каждого графического процессора, а переменные модели одинаково отражаются в разных графических процессорах. Теперь вы можете использовать определенную стратегию следующим образом:
with mirrored_strategy.scope(): model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))]) model.compile(loss='mse', optimizer='sgd') model.fit(X_train, y_train, validation_data=(X_test, y_test), batch_size=128, epochs=10)
Обратите внимание, что приведенный выше фрагмент кода будет полезен только в том случае, если в одной системе настроено несколько графических процессоров. Существует несколько стратегий распределения, которые вы можете настроить. Подробнее об этом можно прочитать здесь.
9. TensorBoard в Jupyter notebook
Это, пожалуй, самая захватывающая часть этого апдейта. Вы можете визуализировать обучение модели непосредственно в Jupyter notebook через TensorBoard. Новый TensorBoard имеет множество интересных функций, таких как профилирование памяти, просмотр данных изображения, включая матрицу неточностей, граф концептуальной модели и так далее. Подробнее об этом можно прочитать здесь.
В этом разделе вы сконфигурируете свою среду так, чтобы TensorBoard отображался в Jupyter. Сначала вам нужно загрузить расширение блокнота tenorboard.notebook:
%load_ext tensorboard.notebook
Теперь вы определите обратный вызов TensorBoard с помощью модуля tf.keras.callbacks.
from datetime import datetime import os # Make a directory to keep the training logs os.mkdir("logs") # Set the callback logdir = "logs" tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=logdir)
Перестройте модель, используя Sequential API tf.keras:
# Define the model model = tf.keras.Sequential([ tf.keras.layers.Dropout(rate=0.2, input_shape=X_train.shape[1:]), tf.keras.layers.Dense(units=64, activation='relu'), tf.keras.layers.Dropout(rate=0.2), tf.keras.layers.Dense(units=64, activation='relu'), tf.keras.layers.Dropout(rate=0.2), tf.keras.layers.Dense(units=1, activation='sigmoid') ]) # Compile the model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
Обучение и тестовые наборы были модифицированы для различных целей. Так что будет хорошо, если разделить их еще раз:
# Split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=7)
Вы все готовы обучать модель:
# The TensorBoard extension %tensorboard --logdir logs/ # Pass the TensorBoard callback you defined model.fit(X_train, y_train, validation_data=(X_test, y_test), batch_size=64, epochs=10, callbacks=[tensorboard_callback], verbose=False)
Панель инструментов TensorBoard должна быть загружена в Jupyter, и вы сможете отслеж��вать метрику обучения и валидации.
0 notes
gorschal · 6 years ago
Text
Multi-Stage Docker на все случаи жизни
Докер еще с версии 17.05 поддерживает Multi-Stage сборку. Не знаю, возможно это мне так везет, но все что удалось почитать на эту тему сводится к сборке максимально минималистичного Golang образа.
Выглядит это примерно так (взял практически из официальной документации):
FROM golang:latest AS builder WORKDIR ./src COPY . . RUN go build ./src/main.go FROM alpine:latest COPY --from=builder /go/main . CMD ["./main"]
При сборке этого образа происходит дословно следующее. Первый блок FROM под названием builder собирает (компилирует) наше Go приложение. Второй блок FROM берет голый alpine образ и вставляет в него артефакт из первого блока (под артефактом подразумевается скомпилированный бинарник).
Если мы выполним нижеследующую команду, то мы действительно, и по понятным причинам получим минимальный из возможных образ.
$ docker build -t ./go-docker:latest .
И здесь начинается самое интересное. Уменьшив размер образа мы удалили из него практически все, в том и числе, и все что связано с компиляцией. Но ведь мы уже привыкли использовать докеры не только в продакшене, но и в девелоп процессах и возможность компиляции для нас критически важна. Так как же совместить эти заведомо противоречие требования? Как по мне, так это и есть основная причина использования Multi-Stage сборок, а отнюдь не размер образа.
В первую очередь Multi-Stage сборка это когда мы можем использовать один и тот же докер файл в массе сценариев. В нашем случае нам просто достаточно добавить в docker-compose один параметр и мы решаем проблему.
version: "3.4" services: go-builder: build: context: . dockerfile: ./Dockerfile target: builder container_name: go-builder
Параметр target: builder говорит нам,что нам необходимо использовать в докере именованный блок builder. И это простое действие позволяет нам ничего не менять в нашем процессе разработки. Все наши компиляторы на месте, но при этом в продакшене наш образ максимально минимизирован. Одни плюсы.
Для наглядности в наш докер файл можно добавить еще один слой. И в разработке уже использовать блок develop.
FROM golang:latest AS develop WORKDIR ./src COPY . . FROM develop AS builder RUN go build ./src/main.go FROM alpine:latest COPY --from=builder /go/main . CMD ["./main"]
Golang это компилируемый язык, а будет ли польза от использования Multi-Stage в интерпретируемых языках. Ведь интерпретатор в них должен присутствовать в любом случае, хоть в девелоп окружении, хоть в продакшене. И ответ, да.
Для примера возьмем Python и у нас имеется две среды: develop и production. А также в наличии три файла requirements. В первом (requirements.txt) содержатся пакеты необходимые для всех используемых сред (например Django). Во втором (requirements.dev.txt) содержатся пакеты необходимые нам в процессе разработки (например coverage). А в третьем (requirements.prod.txt) пакеты необходимые для развертывания приложения (например gunicorn). В данном примере наш docker файл примет примерно такой вид:
FROM python:3.7 AS stage WORKDIR /opt/app ADD requirements.txt /opt/app/ RUN pip install --no-cache-dir -r /opt/app/requirements.txt FROM stage AS develop ADD requirements.dev.txt /opt/app/ RUN pip install --no-cache-dir -r /opt/app/requirements.dev.txt FROM stage AS production ADD requirements.prod.txt /opt/app/ RUN pip install --no-cache-dir -r /opt/app/requirements.prod.txt
Думаю, из контекста все понятно. Но есть один вопрос. Как нам собрать образ для продакшена, ведь в нашем случае туда попадут все три блока, а нам бы хотелось иметь только один production. И в этом нам поможет уже знакомый по docker-compose параметр target. Только этот раз мы его используем уже непосредственно при сборке docker файла.
$ docker build — target production -t ./python-docker:latest .
Осталось только осветить как Multi-Stage дружит с kubernetes. На самом деле никак. В kubernetes нет ничего на эту тему. Какой докер образ пропишем такой и будет. А как собрать докер образ с необходимыми слоями показано чуть выше.
0 notes
gorschal · 6 years ago
Video
youtube
0 notes