-Поиск по дневнику

Поиск сообщений в rss_rss_hh_full

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 1

Habrahabr








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

Абстракция сетевого слоя с применением «стратегий»

Четверг, 21 Сентября 2017 г. 22:51 + в цитатник
iWheelBuy вчера в 22:51 Разработка

Абстракция сетевого слоя с применением «стратегий»

    От всех моих предыдущих реализаций сетевого слоя осталось впечатление, что есть еще куда расти. Данная публикация ставит целью привести один из вариантов архитектурного решения по построению сетевого слоя приложения. Речь пойдет не об очередном способе использования очередного сетевого фреймворка.


    Часть 1. Взгляд на существующие подходы


    Для начала из публикации 21 Amazing Open Source iOS Apps Written in Swift взято приложение Artsy. В нем используется популярный фреймворк Moya, на базе которого и построен весь сетевой слой. Отмечу ряд основных недостатков, которые встретил в данном проекте и часто встречаю в других приложениях и публикациях.


    Повторы цепочек преобразования ответа


    let endpoint: ArtsyAPI = ArtsyAPI.activeAuctions
    provider.request(endpoint)
        .filterSuccessfulStatusCodes()
        .mapJSON()
        .mapTo(arrayOf: Sale.self)

    Разработчик этим кодом обозначил некую логическую цепочку, в которой ответ на запрос activeAuctions преобразуется в массив объектов Sale. При повторном использовании этого запроса в других ViewModel или ViewController разработчику придется копировать запрос вместе с цепочкой преобразования ответа. Чтобы избежать копирования повторяющейся логики преобразования, запрос и ответ можно связать неким контрактом, который будет описан ровно один раз.


    Большое количество зависимостей


    Часто для работы с сетью используются фреймворки Alamofire, Moya и др. В идеале приложение должно минимально зависеть от этих фреймворков. Если в поиске по репозитоию Artsy набрать import Moya, то можно увидеть десятки совпадений. Если вдруг проект решит отказаться от использования Moya — очень много кода придется рефакторить.


    Не сложно оценить, на сколько каждый проект зависит от сетевого фреймворка, если убрать эту зависимость и попробовать доработать приложение до работоспособного состояния.


    Общий класс менедежера запросов


    Возможным выходом из ситуации с зависимостями будет создание специального класса, который будет один знать о фреймворках и обо всех возможных способах получить данные из сети. Эти способы будут описаны функциями со строго типизированными входящими и исходящими параметрами, что в свою очередь будет являться контрактом, упомянутом выше, и поможет справиться с проблемой повторов цепочек преобразования ответа. Такой подход тоже достаточно часто встречается. Его применение на практике можно также найти в приложениях из списка 21 Amazing Open Source iOS Apps Written in Swift. Например, в приложении DesignerNewsApp. Выглядит такой класс следующим образом:


    struct DesignerNewsService {
    
        static func storiesForSection(..., response: ([Story]) -> ()) {
            // parameters
            Alamofire.request(...).response { _ in
                // parsing
            }
        }
    
        static func loginWithEmail(..., response: (token: String?) -> ()) {
            // parameters
            Alamofire.request(...).response { _ in
                // parsing
            }
        }
    }

    У такого подхода также есть минусы. Количество обязанностей, возложенных на этот класс больше, чем того требует принцип единственной ответственности. Его придется менять при смене способа выполнения запросов (замена Alamofire), при смене фреймворка для парсинга, при изменении параметров запроса. Кроме того, такой класс может перерасти в god object или использоваться как singleton со всеми вытекающими последствиями.


    Вам знакомо то чувство уныния, когда нужно интегрировать проект с очередным RESTful API? Это когда в очередной раз нужно создавать какой-нибудь APIManager и наполнять его Alamofire запросами… (ссылка)

    Часть 2. Подход, основанный на стратегиях


    Учитывая все недостатки, описанные в 1-й части публикации, я сформулировал для себя ряд требований к будущему слою работы с сетью:


    • Снизить зависимость от внешних сетевых фреймворков
    • Предусмотреть возможность быстро и легко заменять сетевые фреймворки между собой
    • Использовать по максимому универсальные классы/структуры и протоколы со связанными типами
    • Не допустить повтора цепочек преобразования и свести к минимуму повторяемость кода

    Что получилось в итоге:


    Базовые протоколы сетевого слоя


    Протокол ApiTarget определяет все данные, которые необходимы для формирования запроса (параметры, путь, метод… и др.)


    protocol ApiTarget {
    
        var parameters: [String : String] { get }
    }

    Обобщенный протокол ApiResponseConvertible определяет способ преобразования полученного объекта (в данном случае Data) в объект связанного типа.


    protocol ApiResponseConvertible {
    
        associatedtype ResultType
    
        func map(data: Data) throws -> ResultType
    }

    Протокол ApiService определяет способ отправки запросов. Обычно функция, объявленная в протоколе, принимает замыкание содержащее объект ответа и возможные ошибки. В текущей реализации функция возвращает Observable — объект реактивного фреймворка RxSwift.


    protocol ApiService: class {
    
        func request(with target: T) -> Observable where T: ApiResponseConvertible, T: ApiTarget
    }

    Стратегии


    Стратегией я называю упомянутый в начале публикации контракт, который связывает между собой несколько типов данных. Стратегия является протоколом и выглядит в самом простом случае таким образом:


    protocol Strategy {
    
        associatedtype ObjectType
        associatedtype ResultType
    }

    Для нужд сетевого слоя стратегия должна уметь создавать объект, который можно передать в экземпляр класса, соответствующего протоколу ApiService. Добавим функцию создания объекта в протокол ApiStrategy.


    protocol ApiStrategy {
    
        associatedtype ObjectType
        associatedtype ResultType
    
        static func target(with object: ObjectType) -> AnyTarget
    }

    Введение новой универсальной структуры AnyTarget обусловленно тем, что мы не можем использовать обобщенный протокол ApiResponseConvertible в качестве типа возвращаемого функцией объекта, потому что у протокола есть связанный тип.


    struct AnyTarget: ApiResponseConvertible, ApiTarget {
    
        private let _map: (Data) throws -> T
        let parameters: [String : String]
    
        init(with target: U) where U: ApiResponseConvertible, U: ApiTarget, U.ResultType == T {
            _map = target.map
            parameters = target.parameters
        }
    
        func map(data: Data) throws -> T {
            return try _map(data)
        }
    }

    Вот так выглядит самая примитивная реализация стратегии:


    struct SimpleStrategy: ApiStrategy {
    
        typealias ObjectType = Int
        typealias ResultType = String
    
        static func target(with object: Int) -> AnyTarget {
            let target = Target(value: object)
            return AnyTarget(with: target)
        }
    }
    
    private struct Target {
    
        let value: Int
    }
    
    extension Target: ApiTarget {
    
        var parameters: [String : String] {
            return [:]
        }
    }
    
    extension Target: ApiResponseConvertible {
    
        public func map(data: Data) throws -> String {
            return "\(value)" // map value from data
        }
    }

    Стоит отметить, что структура Target является приватной, т.к. за пределами файла использоваться она не будет. Она нужна лишь для инициализации универсальной структуры AnyTarget.


    Преобразование объекта тоже происходит в рамках файла, поэтому ApiService не будет ничего знать об инструментах, используемых при парсинге.


    Использование стратегий и сервиса


    let service: ApiService = ...
    let target = SimpleStrategy.target(with: ...)
    let request = service.request(with: target)

    Стратегия подскажет, какой объект нужен для осуществления запроса и какой объект будет на выходе. Все строго типизировано стратегией и не требуется указывать типы как в случае с универсальными функциями.


    Реализация ApiService


    Как можно было заметить, в данном подходе сетевой фреймворк остался за пределами основной логики построения сервиса. На первых порах его можно не использовать совсем. Например, если в реализации функции map протокола ApiResponseConvertible возвращать mock-объект, то сервис может быть совсем примитивным классом:


    class MockService: ApiService {
    
        func request(with target: T) -> Observable where T : ApiResponseConvertible, T : ApiTarget {
            return Observable
                .just(Data())
                .map({ [map = target.map] (data) -> T.ResultType in
                    return try map(data)
                })
        }
    }

    Тестовую реализацию и применение протокола ApiService на базе реального сетевого фреймворка Moya можно посмотреть спойлере:


    ApiService + Moya + Реализация
    public extension Api {
    
        public class Service {
    
            public enum Kind {
    
                case failing(Api.Error)
                case normal
                case test
            }
    
            let kind: Api.Service.Kind
            let logs: Bool
            fileprivate lazy var provider: MoyaProvider = self.getProvider()
    
            public init(kind: Api.Service.Kind, logs: Bool) {
                self.kind = kind
                self.logs = logs
            }
    
            fileprivate func getProvider() -> MoyaProvider {
                return MoyaProvider(
                    stubClosure: stubClosure,
                    plugins: plugins
                )
            }
    
            private var plugins: [PluginType] {
                return logs ? [RequestPluginType()] : []
            }
    
            private func stubClosure(_ target: Target) -> Moya.StubBehavior {
                switch kind {
                case .failing, .normal:
                    return Moya.StubBehavior.never
                case .test:
                    return Moya.StubBehavior.immediate
                }
            }
        }
    }
    
    extension Api.Service: ApiService {
    
        public func dispose() {
            //
        }
    
        public func request(headers: [Api.Header: String], scheduler: ImmediateSchedulerType, target: T) -> Observable where T: ApiResponseConvertible, T: ApiTarget {
            switch kind {
            case .failing(let error):
                return Observable.error(error)
            default:
                return Observable
                    .just((), scheduler: scheduler)
                    .map({ [weak self] _ -> MoyaProvider? in
                        return self?.provider
                    })
                    .filterNil()
                    .flatMap({ [headers, target] provider -> Observable in
                        let api = Target(headers: headers, target: target)
                        return provider.rx
                            .request(api)
                            .asObservable()
                    })
                    .map({ [map = target.map] (response: Moya.Response) -> T.ResultType in
                        switch response.statusCode {
                        case 200:
                            return try map(response.data)
                        case 401:
                            throw Api.Error.invalidToken
                        case 404:
                            do {
                                let json: JSON = try response.data.materialize()
                                let message: String = try json["ErrorMessage"].materialize()
                                throw Api.Error.failedWithMessage(message)
                            } catch let error {
                                if case .some(let error) = error as? Api.Error, case .failedWithMessage = error {
                                    throw error
                                } else {
                                    throw Api.Error.failedWithMessage(nil)
                                }
                            }
                        case 500:
                            throw Api.Error.serverInteralError
                        case 501:
                            throw Api.Error.appUpdateRequired
                        default:
                            throw Api.Error.unknown(nil)
                        }
                    })
                    .catchError({ (error) -> Observable in
                        switch error as? Api.Error {
                        case .some(let error):
                            return Observable.error(error)
                        default:
                            let error = Api.Error.unknown(error)
                            return Observable.error(error)
                        }
                    })
            }
        }
    }

    ApiService + Moya + Использование
    func observableRequest(_ observableCancel: Observable, _ observableTextPrepared: Observable) -> Observable> {
        let factoryApiService = base.factoryApiService
        let factoryIndicator = base.factoryIndicator
        let factorySchedulerConcurrent = base.factorySchedulerConcurrent
        return observableTextPrepared
            .observeOn(base.factorySchedulerConcurrent())
            .flatMapLatest(observableCancel: observableCancel, observableFactory: { (text) -> Observable> in
                return Observable
                    .using(factoryApiService) { (service: Api.Service) -> Observable> in
                        let object = Api.Request.Categories.Name(text: text)
                        let target = Api.Strategy.Categories.Auto.target(with: object)
                        let headers = [Api.Header.authorization: ""]
                        let request = service
                            .request(headers: headers, scheduler: factorySchedulerConcurrent(), target: target)
                            .map({ Objects(text: text, manual: true, objects: $0) })
                            .map({ Result(value: $0) })
                            .shareReplayLatestWhileConnected()
                        switch factoryIndicator() {
                        case .some(let activityIndicator):
                            return request.trackActivity(activityIndicator)
                        default:
                            return request
                        }
                    }
                    .catchError({ (error) -> Observable> in
                        switch error as? Api.Error {
                        case .some(let error):
                            return Observable.just(Result(error: error))
                        default:
                            return Observable.just(Result(error: Api.Error.unknown(nil)))
                        }
                    })
            })
            .observeOn(base.factorySchedulerConcurrent())
            .shareReplayLatestWhileConnected()
    }

    Вывод


    Полученный сетевой слой сможет успешно существовать и без стратегий. Точно так же стратегии можно использовать для других целей и задач. Совместное же их использование сделало использование сетевого слоя удобным и понятным.

    Original source: habrahabr.ru (comments, light).

    https://habrahabr.ru/post/338380/


    Метки:  

    Абстракция сетевого слоя с применением «стратегий»

    Четверг, 21 Сентября 2017 г. 22:51 + в цитатник
    iWheelBuy вчера в 22:51 Разработка

    Абстракция сетевого слоя с применением «стратегий»

      От всех моих предыдущих реализаций сетевого слоя осталось впечатление, что есть еще куда расти. Данная публикация ставит целью привести один из вариантов архитектурного решения по построению сетевого слоя приложения. Речь пойдет не об очередном способе использования очередного сетевого фреймворка.


      Часть 1. Взгляд на существующие подходы


      Для начала из публикации 21 Amazing Open Source iOS Apps Written in Swift взято приложение Artsy. В нем используется популярный фреймворк Moya, на базе которого и построен весь сетевой слой. Отмечу ряд основных недостатков, которые встретил в данном проекте и часто встречаю в других приложениях и публикациях.


      Повторы цепочек преобразования ответа


      let endpoint: ArtsyAPI = ArtsyAPI.activeAuctions
      provider.request(endpoint)
          .filterSuccessfulStatusCodes()
          .mapJSON()
          .mapTo(arrayOf: Sale.self)

      Разработчик этим кодом обозначил некую логическую цепочку, в которой ответ на запрос activeAuctions преобразуется в массив объектов Sale. При повторном использовании этого запроса в других ViewModel или ViewController разработчику придется копировать запрос вместе с цепочкой преобразования ответа. Чтобы избежать копирования повторяющейся логики преобразования, запрос и ответ можно связать неким контрактом, который будет описан ровно один раз.


      Большое количество зависимостей


      Часто для работы с сетью используются фреймворки Alamofire, Moya и др. В идеале приложение должно минимально зависеть от этих фреймворков. Если в поиске по репозитоию Artsy набрать import Moya, то можно увидеть десятки совпадений. Если вдруг проект решит отказаться от использования Moya — очень много кода придется рефакторить.


      Не сложно оценить, на сколько каждый проект зависит от сетевого фреймворка, если убрать эту зависимость и попробовать доработать приложение до работоспособного состояния.


      Общий класс менедежера запросов


      Возможным выходом из ситуации с зависимостями будет создание специального класса, который будет один знать о фреймворках и обо всех возможных способах получить данные из сети. Эти способы будут описаны функциями со строго типизированными входящими и исходящими параметрами, что в свою очередь будет являться контрактом, упомянутом выше, и поможет справиться с проблемой повторов цепочек преобразования ответа. Такой подход тоже достаточно часто встречается. Его применение на практике можно также найти в приложениях из списка 21 Amazing Open Source iOS Apps Written in Swift. Например, в приложении DesignerNewsApp. Выглядит такой класс следующим образом:


      struct DesignerNewsService {
      
          static func storiesForSection(..., response: ([Story]) -> ()) {
              // parameters
              Alamofire.request(...).response { _ in
                  // parsing
              }
          }
      
          static func loginWithEmail(..., response: (token: String?) -> ()) {
              // parameters
              Alamofire.request(...).response { _ in
                  // parsing
              }
          }
      }

      У такого подхода также есть минусы. Количество обязанностей, возложенных на этот класс больше, чем того требует принцип единственной ответственности. Его придется менять при смене способа выполнения запросов (замена Alamofire), при смене фреймворка для парсинга, при изменении параметров запроса. Кроме того, такой класс может перерасти в god object или использоваться как singleton со всеми вытекающими последствиями.


      Вам знакомо то чувство уныния, когда нужно интегрировать проект с очередным RESTful API? Это когда в очередной раз нужно создавать какой-нибудь APIManager и наполнять его Alamofire запросами… (ссылка)

      Часть 2. Подход, основанный на стратегиях


      Учитывая все недостатки, описанные в 1-й части публикации, я сформулировал для себя ряд требований к будущему слою работы с сетью:


      • Снизить зависимость от внешних сетевых фреймворков
      • Предусмотреть возможность быстро и легко заменять сетевые фреймворки между собой
      • Использовать по максимому универсальные классы/структуры и протоколы со связанными типами
      • Не допустить повтора цепочек преобразования и свести к минимуму повторяемость кода

      Что получилось в итоге:


      Базовые протоколы сетевого слоя


      Протокол ApiTarget определяет все данные, которые необходимы для формирования запроса (параметры, путь, метод… и др.)


      protocol ApiTarget {
      
          var parameters: [String : String] { get }
      }

      Обобщенный протокол ApiResponseConvertible определяет способ преобразования полученного объекта (в данном случае Data) в объект связанного типа.


      protocol ApiResponseConvertible {
      
          associatedtype ResultType
      
          func map(data: Data) throws -> ResultType
      }

      Протокол ApiService определяет способ отправки запросов. Обычно функция, объявленная в протоколе, принимает замыкание содержащее объект ответа и возможные ошибки. В текущей реализации функция возвращает Observable — объект реактивного фреймворка RxSwift.


      protocol ApiService: class {
      
          func request(with target: T) -> Observable where T: ApiResponseConvertible, T: ApiTarget
      }

      Стратегии


      Стратегией я называю упомянутый в начале публикации контракт, который связывает между собой несколько типов данных. Стратегия является протоколом и выглядит в самом простом случае таким образом:


      protocol Strategy {
      
          associatedtype ObjectType
          associatedtype ResultType
      }

      Для нужд сетевого слоя стратегия должна уметь создавать объект, который можно передать в экземпляр класса, соответствующего протоколу ApiService. Добавим функцию создания объекта в протокол ApiStrategy.


      protocol ApiStrategy {
      
          associatedtype ObjectType
          associatedtype ResultType
      
          static func target(with object: ObjectType) -> AnyTarget
      }

      Введение новой универсальной структуры AnyTarget обусловленно тем, что мы не можем использовать обобщенный протокол ApiResponseConvertible в качестве типа возвращаемого функцией объекта, потому что у протокола есть связанный тип.


      struct AnyTarget: ApiResponseConvertible, ApiTarget {
      
          private let _map: (Data) throws -> T
          let parameters: [String : String]
      
          init(with target: U) where U: ApiResponseConvertible, U: ApiTarget, U.ResultType == T {
              _map = target.map
              parameters = target.parameters
          }
      
          func map(data: Data) throws -> T {
              return try _map(data)
          }
      }

      Вот так выглядит самая примитивная реализация стратегии:


      struct SimpleStrategy: ApiStrategy {
      
          typealias ObjectType = Int
          typealias ResultType = String
      
          static func target(with object: Int) -> AnyTarget {
              let target = Target(value: object)
              return AnyTarget(with: target)
          }
      }
      
      private struct Target {
      
          let value: Int
      }
      
      extension Target: ApiTarget {
      
          var parameters: [String : String] {
              return [:]
          }
      }
      
      extension Target: ApiResponseConvertible {
      
          public func map(data: Data) throws -> String {
              return "\(value)" // map value from data
          }
      }

      Стоит отметить, что структура Target является приватной, т.к. за пределами файла использоваться она не будет. Она нужна лишь для инициализации универсальной структуры AnyTarget.


      Преобразование объекта тоже происходит в рамках файла, поэтому ApiService не будет ничего знать об инструментах, используемых при парсинге.


      Использование стратегий и сервиса


      let service: ApiService = ...
      let target = SimpleStrategy.target(with: ...)
      let request = service.request(with: target)

      Стратегия подскажет, какой объект нужен для осуществления запроса и какой объект будет на выходе. Все строго типизировано стратегией и не требуется указывать типы как в случае с универсальными функциями.


      Реализация ApiService


      Как можно было заметить, в данном подходе сетевой фреймворк остался за пределами основной логики построения сервиса. На первых порах его можно не использовать совсем. Например, если в реализации функции map протокола ApiResponseConvertible возвращать mock-объект, то сервис может быть совсем примитивным классом:


      class MockService: ApiService {
      
          func request(with target: T) -> Observable where T : ApiResponseConvertible, T : ApiTarget {
              return Observable
                  .just(Data())
                  .map({ [map = target.map] (data) -> T.ResultType in
                      return try map(data)
                  })
          }
      }

      Тестовую реализацию и применение протокола ApiService на базе реального сетевого фреймворка Moya можно посмотреть спойлере:


      ApiService + Moya + Реализация
      public extension Api {
      
          public class Service {
      
              public enum Kind {
      
                  case failing(Api.Error)
                  case normal
                  case test
              }
      
              let kind: Api.Service.Kind
              let logs: Bool
              fileprivate lazy var provider: MoyaProvider = self.getProvider()
      
              public init(kind: Api.Service.Kind, logs: Bool) {
                  self.kind = kind
                  self.logs = logs
              }
      
              fileprivate func getProvider() -> MoyaProvider {
                  return MoyaProvider(
                      stubClosure: stubClosure,
                      plugins: plugins
                  )
              }
      
              private var plugins: [PluginType] {
                  return logs ? [RequestPluginType()] : []
              }
      
              private func stubClosure(_ target: Target) -> Moya.StubBehavior {
                  switch kind {
                  case .failing, .normal:
                      return Moya.StubBehavior.never
                  case .test:
                      return Moya.StubBehavior.immediate
                  }
              }
          }
      }
      
      extension Api.Service: ApiService {
      
          public func dispose() {
              //
          }
      
          public func request(headers: [Api.Header: String], scheduler: ImmediateSchedulerType, target: T) -> Observable where T: ApiResponseConvertible, T: ApiTarget {
              switch kind {
              case .failing(let error):
                  return Observable.error(error)
              default:
                  return Observable
                      .just((), scheduler: scheduler)
                      .map({ [weak self] _ -> MoyaProvider? in
                          return self?.provider
                      })
                      .filterNil()
                      .flatMap({ [headers, target] provider -> Observable in
                          let api = Target(headers: headers, target: target)
                          return provider.rx
                              .request(api)
                              .asObservable()
                      })
                      .map({ [map = target.map] (response: Moya.Response) -> T.ResultType in
                          switch response.statusCode {
                          case 200:
                              return try map(response.data)
                          case 401:
                              throw Api.Error.invalidToken
                          case 404:
                              do {
                                  let json: JSON = try response.data.materialize()
                                  let message: String = try json["ErrorMessage"].materialize()
                                  throw Api.Error.failedWithMessage(message)
                              } catch let error {
                                  if case .some(let error) = error as? Api.Error, case .failedWithMessage = error {
                                      throw error
                                  } else {
                                      throw Api.Error.failedWithMessage(nil)
                                  }
                              }
                          case 500:
                              throw Api.Error.serverInteralError
                          case 501:
                              throw Api.Error.appUpdateRequired
                          default:
                              throw Api.Error.unknown(nil)
                          }
                      })
                      .catchError({ (error) -> Observable in
                          switch error as? Api.Error {
                          case .some(let error):
                              return Observable.error(error)
                          default:
                              let error = Api.Error.unknown(error)
                              return Observable.error(error)
                          }
                      })
              }
          }
      }

      ApiService + Moya + Использование
      func observableRequest(_ observableCancel: Observable, _ observableTextPrepared: Observable) -> Observable> {
          let factoryApiService = base.factoryApiService
          let factoryIndicator = base.factoryIndicator
          let factorySchedulerConcurrent = base.factorySchedulerConcurrent
          return observableTextPrepared
              .observeOn(base.factorySchedulerConcurrent())
              .flatMapLatest(observableCancel: observableCancel, observableFactory: { (text) -> Observable> in
                  return Observable
                      .using(factoryApiService) { (service: Api.Service) -> Observable> in
                          let object = Api.Request.Categories.Name(text: text)
                          let target = Api.Strategy.Categories.Auto.target(with: object)
                          let headers = [Api.Header.authorization: ""]
                          let request = service
                              .request(headers: headers, scheduler: factorySchedulerConcurrent(), target: target)
                              .map({ Objects(text: text, manual: true, objects: $0) })
                              .map({ Result(value: $0) })
                              .shareReplayLatestWhileConnected()
                          switch factoryIndicator() {
                          case .some(let activityIndicator):
                              return request.trackActivity(activityIndicator)
                          default:
                              return request
                          }
                      }
                      .catchError({ (error) -> Observable> in
                          switch error as? Api.Error {
                          case .some(let error):
                              return Observable.just(Result(error: error))
                          default:
                              return Observable.just(Result(error: Api.Error.unknown(nil)))
                          }
                      })
              })
              .observeOn(base.factorySchedulerConcurrent())
              .shareReplayLatestWhileConnected()
      }

      Вывод


      Полученный сетевой слой сможет успешно существовать и без стратегий. Точно так же стратегии можно использовать для других целей и задач. Совместное же их использование сделало использование сетевого слоя удобным и понятным.

      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/338380/


      Метки:  

      learnopengl. Уроки 3.1(Assimp) + 3.2(класс Mesh)

      Четверг, 21 Сентября 2017 г. 20:10 + в цитатник
      dima19972525 вчера в 20:10 Разработка

      learnopengl. Уроки 3.1(Assimp) + 3.2(класс Mesh)

      • Tutorial
      OGL3

      Assimp


      Во всех уроках, мы, в основном, использовали нашего маленького друга — контейнер, но через некоторое время, даже наши лучшие друзья становятся немного скучными. В большом графическом приложении, обычно присутствуют много моделей, на которые намного приятнее смотреть, чем на наш статичный контейнер. Хотя, в отличие от контейнера, нам будет очень сложно, вручную, определить все вершины, нормали и текстурные координаты таких сложных моделей, как например дом или человекоподобные персонажи. Вместо этого, мы будем имортировать модели в наше приложение; модели, которые были тщательно нарисованы, в 3D редакторах, таких как Blender, 3DS MAX или Maya.



      Эти, так называемые инструменты 3D моделирования, позволяют художникам создавать сложные модели и применять текстуры к ним с помощью процесса, который называется текстурная развертка (uv-mapping). Инструменты автоматически генерируют все вершинные координаты, вершины нормалей и текстурные координаты, экспортируя их в файл модели. Таким образом, художники имеют обширный набор инструментов для создания высококачественных моделей, не заботясь о технических деталях. Все технические аспекты спрятаны в экспортируемом файле. Мы, как программисты графики, должны позаботится об этих технических деталях.

      Таким образом, наша работа заключается в анализе этих экспортированных файлов модели и извлечении всей соответствующей информации, чтобы мы могли хранить их в формате, который понимает OpenGL. Однако, распространенная проблема заключается в том, что существуют десятки различных форматов файлов, каждый из которых экспортирует данные модели по-своему уникальному способу. Форматы модели, как .obj от Wavefront содержат только данные модели с незначительной информацией материала, такой как цвет модели или диффузные\бликовые карты, в то время как файлы моделей, на основе XML, чрезвычайно обширны и содержат модели, освещения, много информации о материалах, анимацию и многое другое. Формат obj считается легко анализированным. Рекомендуется ознакомиться со структурой файла, например, на странице в википедии. Это должно дать вам базовые сведения о том, как храниться модель в файле формата obj.

      В общем, существует много разных форматов, где хранящаяся структура данных отличается. Поэтому, если мы хотим импортировать модель из этих файлов, нам нужно написать импортер самим, для каждого формата, который мы захотим импортировать. Удачно для нас, для этого есть библиотека.

      Библиотека для загрузки моделей


      Assimp — очень популярная библиотека, для импортирования моделей, которая расшифровывается как Open Asset Import Library. Эта библиотека может импортировать множество различных форматов, содержащие модели, сохраняя данные, которые импортируются, в виде простой иерархической структуры данных. Как только Assimp закончит загрузку моделей, мы сможем получить все нужные нам данные из этой структуры. Без разницы какой формат файлов мы импортируем, обращение к данным в структурах не изменяется, структура остается такой же для всех различных форматов файлов.

      При импорте модели, с помощью Assimp, библиотека загружает всю модель в объект сцены (Scene), содержащий все данные импортированной модели. Затем Assimp создает коллекцию узлов, где каждый узел содержит индексы к данным, хранящимся в объекте сцены, каждый узел может иметь потомка. Простая модель структуры Assimp представлена ниже:
      image


      • Все данные модели содержатся в объекте Scene, как и данные о материалах и полигональной сетки. Scene также содержит ссылку на корневой узел (Root node) сцены.
      • Корневой узел (Root node) может иметь потомков (Child node) (как и остальные узлы) и может иметь индексы, которые указывают на данные полигональной сетки, хранящиеся в массиве объекта сцены mMeshes. Массив mMeshes корневого узла содержит конкретные объекты полигональных сеток, а значения в массиве mMeshes у любого потомка являются лишь индексами для выборки из массива сеток корневого узла.
      • Объект полигональной сетки (Mesh) содержит все соответствующие данные, необходимые для отрисовки: вершинные координаты, вектора нормалей, текстурных координаты, грани и информацию о материале объекта.
      • Полигональная сетка (Mesh) содержит несколько граней. Грани (Faces) представляют собой примитивы объекта (треугольники, квадраты, точки). Они содержат индексы вершин, образующие примитивы. Так как у нас имеются вершины и их индексы, отрисовка происходит намного легче благодаря element buffer objects (Hello Triangle)
      • Так же, полигональная сетка содержит индекс на материальный объект (Material), который имеет несколько функций для получения свойств материала.


      И так, нам нужно сначала загрузить наш объект в объект сцены, рекурсивно извлекать соответствующие объекты полигональной сетки от каждого из узлов (рекурсивно пройдясь по потомкам каждого узла) и обработать каждый элемент полигональной сетки для извлечения вершин, индексов и свойств материала. Результатом является коллекция полигональных сеток, которые мы будем содержать в объекте Model.

      Mesh — набор вершин и треугольников
      Одна сетка (Mesh) — это минимальный набор данных, необходимый для вывода средствами OpenGL(данные вершин, индексов, материала). Модель же, обычно, состоит из нескольких сеток. При моделировании объектов в специальных программах(Blender, 3D max), художники не создают целую модель из одной формы. Обычно, каждая модель имеет несколько под-моделей\форм, из которых она состоит. Подумайте о человеке, как о модели: художник обычно моделирует голову, конечности, одежду, оружие, все как отдельные компоненты, затем объединив все под-модели, получает исходную.


      В следующих уроках мы создадим наши собственные классы Model и Mesh, которые загружают и хранят импортированные модели, используя только что описанную структуру. Если мы хотим нарисовать модель, то мы выводим ее не целиком, а осуществляем вывод каждой из составляющих модель сеток по-отдельности. До того, как мы сможем имортировать модели, нам нужно сначала включить Assimp в наш проект.

      Сборка Assimp


      Вы можете скачать Assimp с этой страницы, выбрав соответствующую версию. Во время написания статьи, последняя версия Assimp была 3.1.1. Рекомендуется компилировать библиотеки самостоятельно, так как их, предварительно скомпилированые библиотеки, не работают на большинстве систем. Пересмотрите урок Создание окна, если вы забыли как компилировать библиотеку самим, используя CMake.

      Несколько проблем появлялись во время сборки Assimp, так что я отмечу их здесь, с их решениями в случае, если кто-либо из вас получит те же ошибки:

      • CMake выдает ошибки о отсутствующих библиотеках DiretX, такие как:
        Could not locate DirectX
        CMake Error at cmake-modules/FindPkgMacros.cmake:110 (message):
        Required library DirectX not found! Install the library (including dev packages)
        and try again. If the library is already installed, set the missing variables
        manually in cmake.

        Нужно установить DirectX SDK, в случае если он не был установлен. Вы можете скачать SDK здесь .
      • Во время установка DirectX SDK выскакивает код ошибки s1023.
        В этом случае вам сначала нужно установить пакет С++, до того как устанавливать SDK,
        как описано здесь.

      • После завершения настройки можно создать файл проекта, открыть его и скомпилировать библиотеки.
      • По умолчанию, Assimp предоставляется в виде динамической библиотеки, поэтому нам нужно включить в проект соответствующую dll с именем assimp.DLL. Можно просто файл библиотеку DLL в ту же папку, где находится исполняемый файл приложения.
      • После компиляции, библиотека и её dll файл будут находится в папках code/Debug или code/Release.
      • Далее просто свяжите файл библиотеки и dll файл с вашим проектом, и убедитесь, что вы не забыли также подключить заголовочные файлы Assimp.

      Если вы хотите использовать многопоточность для увеличения производительности, вы можете собрать Assimp с Boost. Полная инструкция находится здесь.

      На этом моменте, вы должны были скомпилировать Assimp и внедрить его в ваше приложение.

      Класс Mesh


      Используя Assimp мы можем загружать множество различных моделей в наше приложение, но после загрузки, данные все ещё хранятся в структуре Assimp. Нам нужно преобразовать эти данные в формат, который понимает OpenGL, чтобы мы смогли отрисовать модель. В предыдущем уроке мы узнали, что полигональная сетка представляет собой одну рисуемую сущность, поэтому давайте начнем с определения собственного класса Mesh.

      Давайте подумаем, какой набор данных нам нужен для нашего класса. Полигональная сетка нуждается в наборе вершин, где каждая вершина содержит вектор позиции, вектор нормали и вектор текстурных координат. Полигональная сетка также должна содержать индексы,
      для индексированной отрисовки, и данные для материалов.

      Теперь, мы можем определить структуру вершины:
      struct Vertex {
          glm::vec3 Position;
          glm::vec3 Normal;
          glm::vec2 TexCoords;
      };

      Каждая вершина хранится в структуре Vertex, которая может использоваться для индексации каждой вершины. Помимо структуры Vertex, нам также нужно создать структуру, которая хранит текстурные данные.
      struct Texture {
          unsigned int id;
          string type;
      }; 

      Она хранит id и тип текстуры (диффузная или бликовая).

      Написав структуры, можно начинать писать наш класс:
      class Mesh {
          public:
              /*  Mesh Data  */
              vector vertices;
              vector indices;
              vector textures;
              /*  Functions  */
              Mesh(vector vertices, vector indices, vector textures);
              void Draw(Shader shader);
          private:
              /*  Render data  */
              unsigned int VAO, VBO, EBO;
              /*  Functions    */
              void setupMesh();
      };

      Как вы можете видеть, класс не очень сложен. Конструктор принимает все нужные нам данные, в методе setupMesh мы инициализируем буферы, в методе Draw мы будем отрисовывать нашу полигональную сетку. Обратите внимание, что функция отрисовки (Draw), принимает объект шейдера, чтобы мы могли установить соответствующие uniform переменные, до отрисовки.

      Код конструктора довольно прост, мы просто присваиваем аргументам класса, соответствующие аргуметы. Также мы вызываем функцию setupMesh:
      Mesh(vector vertices, vector indices, vector textures)
      {
          this->vertices = vertices;
          this->indices = indices;
          this->textures = textures;
      
          setupMesh();
      }


      Как видите, ничего необычного здесь не происходит. Далее, переходим к функции setupMesh.

      Инициализация


      Благодаря конструктору, у нас имеется все нужные нам данные, которые мы можем использовать для отрисовки. Однако, нам сначала нужно настроить соответствующие буферы. К этому моменту у вас не должно быть проблем с этими понятиями, но, возможно, мы вас немного удивим как можно передавать данные в буфер, которые находятся в структуре:
      void setupMesh()
      {
          glGenVertexArrays(1, &VAO);
          glGenBuffers(1, &VBO);
          glGenBuffers(1, &EBO);
        
          glBindVertexArray(VAO);
          glBindBuffer(GL_ARRAY_BUFFER, VBO);
      
          glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);  
      
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
          glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), 
                       &indices[0], GL_STATIC_DRAW);
      
          // vertex positions
          glEnableVertexAttribArray(0);	
          glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
          // vertex normals
          glEnableVertexAttribArray(1);	
          glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
          // vertex texture coords
          glEnableVertexAttribArray(2);	
          glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
      
          glBindVertexArray(0);
      }  


      Код не сильно отличается от того, что вы ожидали, но несколько маленьких трюков были использованы с помощью структуры Vertex.

      В С++, у структур есть отличное свойство — их память является последовательной. То есть, если бы мы представили структуру как массив данных, то она содержала бы переменные в том порядке, в котором они определены в самой структуре. Например, если мы наполним структуру Vertex, какими нибудь значениями, то их размещение в памяти будет равной:
      Vertex vertex;
      vertex.Position  = glm::vec3(0.2f, 0.4f, 0.6f);
      vertex.Normal    = glm::vec3(0.0f, 1.0f, 0.0f);
      vertex.TexCoords = glm::vec2(1.0f, 0.0f);
      // = [0.2f, 0.4f, 0.6f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f];


      Благодаря этому свойству, например, если мы применим функцию sizeof к нашей структуре, она вернет размер все аргументов, которые в ней определены. Она должна весить 32 байта
      (8 * 4 — размер 1 float). Мы можем это использовать для функции glBufferData:
      glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices[0], GL_STATIC_DRAW);


      Также мы используем макрокоманду offsetof, которая в качестве первого аргумента принимает структуру, а в качестве второго — имя переменной структуры. А возвращает она смещение в байтах указанной структуры, до переменной, переданной во втором аргументе. Это идеально подходит для определения последнего параметра функции glVertexAttribPointer:
      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));


      Смещение теперь определяется с помощью макроса offsetof, который, в данном случае, устанавливает смещение байта для вектора нормали. Обратите также, что мы указываем размер шага равным размеру структуры.

      Использование такой структуры не только обеспечивает более читаемый код, но и позволит нам, в будущем, её расширять. Если мы захотим использовать какой нибудь другой вершинный артрибут, мы сможем легко добавить его в нашу структуру и из-за своей гибкости, код не поломается.

      Отрисовка


      Последняя функция, которую нам следует написать — это Draw. Но перед тем, как отрисовать наши полигоны, сначала нам нужно связать наши текстуры, до вызова функции glDrawElements. Однако, это немного тяжело, т.к. мы не знаем сколько у нас есть текстур (если они вообще есть) и какого они типа. И также, как установить текстурные блоки и текстурных объектов в шейдере?

      Чтобы решить эту проблему, мы примем некоторые соглашения об именовании: каждая диффузная текстура называется texture_diffuseN, а каждая бликовая текстурная карта должна называться texture_specularN, где N-любое число, начиная с 1 до максимального количества разрешенных текстур. Допустим у нас есть 3 диффузные текстуры и 2 бликовые текстуры для конкретной полигональной сетки, мы должны определить их так:
      uniform sampler2D texture_diffuse1;
      uniform sampler2D texture_diffuse2;
      uniform sampler2D texture_diffuse3;
      uniform sampler2D texture_specular1;
      uniform sampler2D texture_specular2;


      Благодаря этому соглашению, мы можем определить столько текстурных объектов, сколько захотим, и если полигональная сетка действительно содержит много текстур, мы знаем, какими будут их имена. Мы можем обрабатывать любое количество текстур на одной полигональной сетке и разработчик может свободно использовать столько текстур, сколько он хочет, просто определяя дополнительные текстурные объекты в шейдере.

      Кроме этого решения, есть также много других, и если вам не нравится это, вы можете проявить свою творческую способность и придумать свое собственное решение.


      Код метода Draw:
      void Draw(Shader shader) 
      {
          unsigned int diffuseNr = 1;
          unsigned int specularNr = 1;
          for(unsigned int i = 0; i < textures.size(); i++)
          {
              glActiveTexture(GL_TEXTURE0 + i); // активируем текстурный блок, до привязки
              // получаем номер текстуры
              stringstream ss;
              string number;
              string name = textures[i].type;
              if(name == "texture_diffuse")
                  ss << diffuseNr++; // передаем unsigned int в stream
              else if(name == "texture_specular")
                  ss << specularNr++; // передаем unsigned int в stream
              number = ss.str(); 
      
              shader.setFloat(("material." + name + number).c_str(), i);
              glBindTexture(GL_TEXTURE_2D, textures[i].id);
          }
          glActiveTexture(GL_TEXTURE0);
      
          // отрисовывем полигональную сетку
          glBindVertexArray(VAO);
          glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
          glBindVertexArray(0);
      }  


      Это не самый красивый код, но отчасти в этом виноват С++, так как, например, в нем нет такого преобразования типов, как int в строку. Мы пробегаемся по N-текстурам и определяем присваиваем их типы строковой переменной, что бы затем мы имели преставление, какой номер конкретного типа текстуры. Далее, мы узнаём номер нашего текстурного объекта, ну и наконец, устанавливаем этому текстурному объекту номер, соответствующий активному текстурному блоку и связываем текстуру. Обратите внимание, что мы собираемся хранить текстурные объекты в структуре Material, как обычно мы и делали.

      Обратите внимание, что увеличив диффузные и бликовые счетчики, мы сразу передаем их в stringstream. Правый инкремент в C++ увеличивает значение на 1, но возвращает старое значение.


      Вы можете найти полный код класса Mesh здесь.

      В следующем уроке, мы создадим класс Model, который работает как контейнер, для объектов класса Mesh и фактически реализует интерфейс загрузки Assimp.
      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/338436/


      Метки:  

      learnopengl. Уроки 3.1(Assimp) + 3.2(класс Mesh)

      Четверг, 21 Сентября 2017 г. 20:10 + в цитатник
      dima19972525 вчера в 20:10 Разработка

      learnopengl. Уроки 3.1(Assimp) + 3.2(класс Mesh)

      • Tutorial
      OGL3

      Assimp


      Во всех уроках, мы, в основном, использовали нашего маленького друга — контейнер, но через некоторое время, даже наши лучшие друзья становятся немного скучными. В большом графическом приложении, обычно присутствуют много моделей, на которые намного приятнее смотреть, чем на наш статичный контейнер. Хотя, в отличие от контейнера, нам будет очень сложно, вручную, определить все вершины, нормали и текстурные координаты таких сложных моделей, как например дом или человекоподобные персонажи. Вместо этого, мы будем имортировать модели в наше приложение; модели, которые были тщательно нарисованы, в 3D редакторах, таких как Blender, 3DS MAX или Maya.



      Эти, так называемые инструменты 3D моделирования, позволяют художникам создавать сложные модели и применять текстуры к ним с помощью процесса, который называется текстурная развертка (uv-mapping). Инструменты автоматически генерируют все вершинные координаты, вершины нормалей и текстурные координаты, экспортируя их в файл модели. Таким образом, художники имеют обширный набор инструментов для создания высококачественных моделей, не заботясь о технических деталях. Все технические аспекты спрятаны в экспортируемом файле. Мы, как программисты графики, должны позаботится об этих технических деталях.

      Таким образом, наша работа заключается в анализе этих экспортированных файлов модели и извлечении всей соответствующей информации, чтобы мы могли хранить их в формате, который понимает OpenGL. Однако, распространенная проблема заключается в том, что существуют десятки различных форматов файлов, каждый из которых экспортирует данные модели по-своему уникальному способу. Форматы модели, как .obj от Wavefront содержат только данные модели с незначительной информацией материала, такой как цвет модели или диффузные\бликовые карты, в то время как файлы моделей, на основе XML, чрезвычайно обширны и содержат модели, освещения, много информации о материалах, анимацию и многое другое. Формат obj считается легко анализированным. Рекомендуется ознакомиться со структурой файла, например, на странице в википедии. Это должно дать вам базовые сведения о том, как храниться модель в файле формата obj.

      В общем, существует много разных форматов, где хранящаяся структура данных отличается. Поэтому, если мы хотим импортировать модель из этих файлов, нам нужно написать импортер самим, для каждого формата, который мы захотим импортировать. Удачно для нас, для этого есть библиотека.

      Библиотека для загрузки моделей


      Assimp — очень популярная библиотека, для импортирования моделей, которая расшифровывается как Open Asset Import Library. Эта библиотека может импортировать множество различных форматов, содержащие модели, сохраняя данные, которые импортируются, в виде простой иерархической структуры данных. Как только Assimp закончит загрузку моделей, мы сможем получить все нужные нам данные из этой структуры. Без разницы какой формат файлов мы импортируем, обращение к данным в структурах не изменяется, структура остается такой же для всех различных форматов файлов.

      При импорте модели, с помощью Assimp, библиотека загружает всю модель в объект сцены (Scene), содержащий все данные импортированной модели. Затем Assimp создает коллекцию узлов, где каждый узел содержит индексы к данным, хранящимся в объекте сцены, каждый узел может иметь потомка. Простая модель структуры Assimp представлена ниже:
      image


      • Все данные модели содержатся в объекте Scene, как и данные о материалах и полигональной сетки. Scene также содержит ссылку на корневой узел (Root node) сцены.
      • Корневой узел (Root node) может иметь потомков (Child node) (как и остальные узлы) и может иметь индексы, которые указывают на данные полигональной сетки, хранящиеся в массиве объекта сцены mMeshes. Массив mMeshes корневого узла содержит конкретные объекты полигональных сеток, а значения в массиве mMeshes у любого потомка являются лишь индексами для выборки из массива сеток корневого узла.
      • Объект полигональной сетки (Mesh) содержит все соответствующие данные, необходимые для отрисовки: вершинные координаты, вектора нормалей, текстурных координаты, грани и информацию о материале объекта.
      • Полигональная сетка (Mesh) содержит несколько граней. Грани (Faces) представляют собой примитивы объекта (треугольники, квадраты, точки). Они содержат индексы вершин, образующие примитивы. Так как у нас имеются вершины и их индексы, отрисовка происходит намного легче благодаря element buffer objects (Hello Triangle)
      • Так же, полигональная сетка содержит индекс на материальный объект (Material), который имеет несколько функций для получения свойств материала.


      И так, нам нужно сначала загрузить наш объект в объект сцены, рекурсивно извлекать соответствующие объекты полигональной сетки от каждого из узлов (рекурсивно пройдясь по потомкам каждого узла) и обработать каждый элемент полигональной сетки для извлечения вершин, индексов и свойств материала. Результатом является коллекция полигональных сеток, которые мы будем содержать в объекте Model.

      Mesh — набор вершин и треугольников
      Одна сетка (Mesh) — это минимальный набор данных, необходимый для вывода средствами OpenGL(данные вершин, индексов, материала). Модель же, обычно, состоит из нескольких сеток. При моделировании объектов в специальных программах(Blender, 3D max), художники не создают целую модель из одной формы. Обычно, каждая модель имеет несколько под-моделей\форм, из которых она состоит. Подумайте о человеке, как о модели: художник обычно моделирует голову, конечности, одежду, оружие, все как отдельные компоненты, затем объединив все под-модели, получает исходную.


      В следующих уроках мы создадим наши собственные классы Model и Mesh, которые загружают и хранят импортированные модели, используя только что описанную структуру. Если мы хотим нарисовать модель, то мы выводим ее не целиком, а осуществляем вывод каждой из составляющих модель сеток по-отдельности. До того, как мы сможем имортировать модели, нам нужно сначала включить Assimp в наш проект.

      Сборка Assimp


      Вы можете скачать Assimp с этой страницы, выбрав соответствующую версию. Во время написания статьи, последняя версия Assimp была 3.1.1. Рекомендуется компилировать библиотеки самостоятельно, так как их, предварительно скомпилированые библиотеки, не работают на большинстве систем. Пересмотрите урок Создание окна, если вы забыли как компилировать библиотеку самим, используя CMake.

      Несколько проблем появлялись во время сборки Assimp, так что я отмечу их здесь, с их решениями в случае, если кто-либо из вас получит те же ошибки:

      • CMake выдает ошибки о отсутствующих библиотеках DiretX, такие как:
        Could not locate DirectX
        CMake Error at cmake-modules/FindPkgMacros.cmake:110 (message):
        Required library DirectX not found! Install the library (including dev packages)
        and try again. If the library is already installed, set the missing variables
        manually in cmake.

        Нужно установить DirectX SDK, в случае если он не был установлен. Вы можете скачать SDK здесь .
      • Во время установка DirectX SDK выскакивает код ошибки s1023.
        В этом случае вам сначала нужно установить пакет С++, до того как устанавливать SDK,
        как описано здесь.

      • После завершения настройки можно создать файл проекта, открыть его и скомпилировать библиотеки.
      • По умолчанию, Assimp предоставляется в виде динамической библиотеки, поэтому нам нужно включить в проект соответствующую dll с именем assimp.DLL. Можно просто файл библиотеку DLL в ту же папку, где находится исполняемый файл приложения.
      • После компиляции, библиотека и её dll файл будут находится в папках code/Debug или code/Release.
      • Далее просто свяжите файл библиотеки и dll файл с вашим проектом, и убедитесь, что вы не забыли также подключить заголовочные файлы Assimp.

      Если вы хотите использовать многопоточность для увеличения производительности, вы можете собрать Assimp с Boost. Полная инструкция находится здесь.

      На этом моменте, вы должны были скомпилировать Assimp и внедрить его в ваше приложение.

      Класс Mesh


      Используя Assimp мы можем загружать множество различных моделей в наше приложение, но после загрузки, данные все ещё хранятся в структуре Assimp. Нам нужно преобразовать эти данные в формат, который понимает OpenGL, чтобы мы смогли отрисовать модель. В предыдущем уроке мы узнали, что полигональная сетка представляет собой одну рисуемую сущность, поэтому давайте начнем с определения собственного класса Mesh.

      Давайте подумаем, какой набор данных нам нужен для нашего класса. Полигональная сетка нуждается в наборе вершин, где каждая вершина содержит вектор позиции, вектор нормали и вектор текстурных координат. Полигональная сетка также должна содержать индексы,
      для индексированной отрисовки, и данные для материалов.

      Теперь, мы можем определить структуру вершины:
      struct Vertex {
          glm::vec3 Position;
          glm::vec3 Normal;
          glm::vec2 TexCoords;
      };

      Каждая вершина хранится в структуре Vertex, которая может использоваться для индексации каждой вершины. Помимо структуры Vertex, нам также нужно создать структуру, которая хранит текстурные данные.
      struct Texture {
          unsigned int id;
          string type;
      }; 

      Она хранит id и тип текстуры (диффузная или бликовая).

      Написав структуры, можно начинать писать наш класс:
      class Mesh {
          public:
              /*  Mesh Data  */
              vector vertices;
              vector indices;
              vector textures;
              /*  Functions  */
              Mesh(vector vertices, vector indices, vector textures);
              void Draw(Shader shader);
          private:
              /*  Render data  */
              unsigned int VAO, VBO, EBO;
              /*  Functions    */
              void setupMesh();
      };

      Как вы можете видеть, класс не очень сложен. Конструктор принимает все нужные нам данные, в методе setupMesh мы инициализируем буферы, в методе Draw мы будем отрисовывать нашу полигональную сетку. Обратите внимание, что функция отрисовки (Draw), принимает объект шейдера, чтобы мы могли установить соответствующие uniform переменные, до отрисовки.

      Код конструктора довольно прост, мы просто присваиваем аргументам класса, соответствующие аргуметы. Также мы вызываем функцию setupMesh:
      Mesh(vector vertices, vector indices, vector textures)
      {
          this->vertices = vertices;
          this->indices = indices;
          this->textures = textures;
      
          setupMesh();
      }


      Как видите, ничего необычного здесь не происходит. Далее, переходим к функции setupMesh.

      Инициализация


      Благодаря конструктору, у нас имеется все нужные нам данные, которые мы можем использовать для отрисовки. Однако, нам сначала нужно настроить соответствующие буферы. К этому моменту у вас не должно быть проблем с этими понятиями, но, возможно, мы вас немного удивим как можно передавать данные в буфер, которые находятся в структуре:
      void setupMesh()
      {
          glGenVertexArrays(1, &VAO);
          glGenBuffers(1, &VBO);
          glGenBuffers(1, &EBO);
        
          glBindVertexArray(VAO);
          glBindBuffer(GL_ARRAY_BUFFER, VBO);
      
          glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);  
      
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
          glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), 
                       &indices[0], GL_STATIC_DRAW);
      
          // vertex positions
          glEnableVertexAttribArray(0);	
          glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
          // vertex normals
          glEnableVertexAttribArray(1);	
          glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
          // vertex texture coords
          glEnableVertexAttribArray(2);	
          glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
      
          glBindVertexArray(0);
      }  


      Код не сильно отличается от того, что вы ожидали, но несколько маленьких трюков были использованы с помощью структуры Vertex.

      В С++, у структур есть отличное свойство — их память является последовательной. То есть, если бы мы представили структуру как массив данных, то она содержала бы переменные в том порядке, в котором они определены в самой структуре. Например, если мы наполним структуру Vertex, какими нибудь значениями, то их размещение в памяти будет равной:
      Vertex vertex;
      vertex.Position  = glm::vec3(0.2f, 0.4f, 0.6f);
      vertex.Normal    = glm::vec3(0.0f, 1.0f, 0.0f);
      vertex.TexCoords = glm::vec2(1.0f, 0.0f);
      // = [0.2f, 0.4f, 0.6f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f];


      Благодаря этому свойству, например, если мы применим функцию sizeof к нашей структуре, она вернет размер все аргументов, которые в ней определены. Она должна весить 32 байта
      (8 * 4 — размер 1 float). Мы можем это использовать для функции glBufferData:
      glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices[0], GL_STATIC_DRAW);


      Также мы используем макрокоманду offsetof, которая в качестве первого аргумента принимает структуру, а в качестве второго — имя переменной структуры. А возвращает она смещение в байтах указанной структуры, до переменной, переданной во втором аргументе. Это идеально подходит для определения последнего параметра функции glVertexAttribPointer:
      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));


      Смещение теперь определяется с помощью макроса offsetof, который, в данном случае, устанавливает смещение байта для вектора нормали. Обратите также, что мы указываем размер шага равным размеру структуры.

      Использование такой структуры не только обеспечивает более читаемый код, но и позволит нам, в будущем, её расширять. Если мы захотим использовать какой нибудь другой вершинный артрибут, мы сможем легко добавить его в нашу структуру и из-за своей гибкости, код не поломается.

      Отрисовка


      Последняя функция, которую нам следует написать — это Draw. Но перед тем, как отрисовать наши полигоны, сначала нам нужно связать наши текстуры, до вызова функции glDrawElements. Однако, это немного тяжело, т.к. мы не знаем сколько у нас есть текстур (если они вообще есть) и какого они типа. И также, как установить текстурные блоки и текстурных объектов в шейдере?

      Чтобы решить эту проблему, мы примем некоторые соглашения об именовании: каждая диффузная текстура называется texture_diffuseN, а каждая бликовая текстурная карта должна называться texture_specularN, где N-любое число, начиная с 1 до максимального количества разрешенных текстур. Допустим у нас есть 3 диффузные текстуры и 2 бликовые текстуры для конкретной полигональной сетки, мы должны определить их так:
      uniform sampler2D texture_diffuse1;
      uniform sampler2D texture_diffuse2;
      uniform sampler2D texture_diffuse3;
      uniform sampler2D texture_specular1;
      uniform sampler2D texture_specular2;


      Благодаря этому соглашению, мы можем определить столько текстурных объектов, сколько захотим, и если полигональная сетка действительно содержит много текстур, мы знаем, какими будут их имена. Мы можем обрабатывать любое количество текстур на одной полигональной сетке и разработчик может свободно использовать столько текстур, сколько он хочет, просто определяя дополнительные текстурные объекты в шейдере.

      Кроме этого решения, есть также много других, и если вам не нравится это, вы можете проявить свою творческую способность и придумать свое собственное решение.


      Код метода Draw:
      void Draw(Shader shader) 
      {
          unsigned int diffuseNr = 1;
          unsigned int specularNr = 1;
          for(unsigned int i = 0; i < textures.size(); i++)
          {
              glActiveTexture(GL_TEXTURE0 + i); // активируем текстурный блок, до привязки
              // получаем номер текстуры
              stringstream ss;
              string number;
              string name = textures[i].type;
              if(name == "texture_diffuse")
                  ss << diffuseNr++; // передаем unsigned int в stream
              else if(name == "texture_specular")
                  ss << specularNr++; // передаем unsigned int в stream
              number = ss.str(); 
      
              shader.setFloat(("material." + name + number).c_str(), i);
              glBindTexture(GL_TEXTURE_2D, textures[i].id);
          }
          glActiveTexture(GL_TEXTURE0);
      
          // отрисовывем полигональную сетку
          glBindVertexArray(VAO);
          glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
          glBindVertexArray(0);
      }  


      Это не самый красивый код, но отчасти в этом виноват С++, так как, например, в нем нет такого преобразования типов, как int в строку. Мы пробегаемся по N-текстурам и определяем присваиваем их типы строковой переменной, что бы затем мы имели преставление, какой номер конкретного типа текстуры. Далее, мы узнаём номер нашего текстурного объекта, ну и наконец, устанавливаем этому текстурному объекту номер, соответствующий активному текстурному блоку и связываем текстуру. Обратите внимание, что мы собираемся хранить текстурные объекты в структуре Material, как обычно мы и делали.

      Обратите внимание, что увеличив диффузные и бликовые счетчики, мы сразу передаем их в stringstream. Правый инкремент в C++ увеличивает значение на 1, но возвращает старое значение.


      Вы можете найти полный код класса Mesh здесь.

      В следующем уроке, мы создадим класс Model, который работает как контейнер, для объектов класса Mesh и фактически реализует интерфейс загрузки Assimp.
      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/338436/


      Метки:  

      День открытых дверей «Лаборатории Касперского»: закрываем данные от взлома, открываем новые возможности

      Четверг, 21 Сентября 2017 г. 17:43 + в цитатник
      Выше головы не прыгнешь. Это утверждение вполне описывает карьерные перспективы талантливого специалиста в крупной стабильной компании. Многообещающему сотруднику гарантируют стабильную зарплату и «печеньки за счет заведения», но ограничивают в выборе проекта, спектра решаемых задач и, откровенно говоря, устанавливают потолок роста (выше руководителя направления программист вряд ли сможет подняться). Именно поэтому сегодня молодых айтишников привлекает уже не карьерный рост, а возможность развивать собственные проекты. Читать далее

      https://habrahabr.ru/post/338224/


      Метки:  

      День открытых дверей «Лаборатории Касперского»: закрываем данные от взлома, открываем новые возможности

      Четверг, 21 Сентября 2017 г. 17:43 + в цитатник
      Выше головы не прыгнешь. Это утверждение вполне описывает карьерные перспективы талантливого специалиста в крупной стабильной компании. Многообещающему сотруднику гарантируют стабильную зарплату и «печеньки за счет заведения», но ограничивают в выборе проекта, спектра решаемых задач и, откровенно говоря, устанавливают потолок роста (выше руководителя направления программист вряд ли сможет подняться). Именно поэтому сегодня молодых айтишников привлекает уже не карьерный рост, а возможность развивать собственные проекты. Читать далее

      https://habrahabr.ru/post/338224/


      Метки:  

      День открытых дверей «Лаборатории Касперского»: закрываем данные от взлома, открываем новые возможности

      Четверг, 21 Сентября 2017 г. 17:43 + в цитатник
      Выше головы не прыгнешь. Это утверждение вполне описывает карьерные перспективы талантливого специалиста в крупной стабильной компании. Многообещающему сотруднику гарантируют стабильную зарплату и «печеньки за счет заведения», но ограничивают в выборе проекта, спектра решаемых задач и, откровенно говоря, устанавливают потолок роста (выше руководителя направления программист вряд ли сможет подняться). Именно поэтому сегодня молодых айтишников привлекает уже не карьерный рост, а возможность развивать собственные проекты. Читать далее

      https://habrahabr.ru/post/338224/


      Метки:  

      День открытых дверей «Лаборатории Касперского»: закрываем данные от взлома, открываем новые возможности

      Четверг, 21 Сентября 2017 г. 17:43 + в цитатник
      Выше головы не прыгнешь. Это утверждение вполне описывает карьерные перспективы талантливого специалиста в крупной стабильной компании. Многообещающему сотруднику гарантируют стабильную зарплату и «печеньки за счет заведения», но ограничивают в выборе проекта, спектра решаемых задач и, откровенно говоря, устанавливают потолок роста (выше руководителя направления программист вряд ли сможет подняться). Именно поэтому сегодня молодых айтишников привлекает уже не карьерный рост, а возможность развивать собственные проекты. Читать далее

      https://habrahabr.ru/post/338224/


      Метки:  

      Достижения в глубоком обучении за последний год

      Четверг, 21 Сентября 2017 г. 17:28 + в цитатник
      EdT сегодня в 17:28 Разработка

      Достижения в глубоком обучении за последний год


        Привет, Хабр. В своей статье я расскажу вам, что интересного произошло в мире машинного обучения за последний год (в основном в Deep Learning). А произошло очень многое, поэтому я остановился на самых, на мой взгляд, зрелищных и/или значимых достижениях. Технические аспекты улучшения архитектур сетей в статье не приводятся. Расширяем кругозор!


        1. Текст


        1.1. Google Neural Machine Translation


        Почти год назад Google анонсировала запуск новой модели для Google Translate. Компания подробно описала архитектуру сети — Recurrent Neural Network (RNN) — в своей статье.



        Основной результат: сокращение отставания от человека по точности перевода на 55—85 % (оценивали люди по 6-балльной шкале). Воспроизвести высокие результаты этой модели сложно без огромного датасета, который имеется у Google.


        image


        2.1. Переговоры. Будет сделка?


        Вы могли слышать дурацкие новости о том, что Facebook выключила своего чат-бота, который вышел из-под контроля и выдумал свой язык. Этого чат-бота компания создала для переговоров. Его цель — вести текстовые переговоры с другим агентом и достичь сделки: как разделить на двоих предметы (книги, шляпы...). У каждого агента своя цель в переговорах, другой ее не знает. Просто уйти с переговоров без сделки нельзя.


        Для обучения собрали датасет человеческих переговоров, обучили supervised рекуррентную сеть, далее уже обученного агента с помощью reinforcement learning (обучения с подкреплением) тренировали переговариваться с самим собой, поставив ограничение: похожесть языка на человеческий.


        Бот научился одной из стратегий реальных переговоров — показывать поддельный интерес к некоторым аспектам сделки, чтобы потом по ним уступить, получив выгоду по своим настоящим целям. Это первая попытка создания подобного переговорного бота, и довольно удачная.


        image


        Подробности — в статье, код выложен в открытый доступ.


        Разумеется, новость о том, что бот якобы придумал язык, раздули на пустом месте. При обучении (при переговорах с таким же агентом) отключили ограничение похожести текста на человеческий, и алгоритм модифицировал язык взаимодействия. Ничего необычного.




        За последний год рекуррентные сети активно развивали и использовали во многих задачах и приложениях. Архитектуры рекуррентных сетей сильно усложнились, однако по некоторым направлениям похожих результатов достигают и простые feedforward-сети — DSSM. Например, Google для своей почтовой фичи Smart Reply достигла такого же качества, как и с LSTM до этого. А Яндекс запустил новый поисковый движок на основе таких сетей.


        2. Речь


        2.1. WaveNet: генерирующая модель для необработанного аудио


        Сотрудники DeepMind (компания, известная своим ботом для игры в го, ныне принадлежащая Google) рассказали в своей статье про генерирование аудио.


        Если коротко, то исследователи сделали авторегрессионную полносверточную модель WaveNet на основе предыдущих подходов к генерированию изображений (PixelRNN и PixelCNN).



        Сеть обучалась end-to-end: на вход текст, на выход аудио. Результат превосходный, разница с человеком сократилась на 50 %.


        image


        Основной недостаток сети — низкая производительность, потому что из-за авторегрессии звуки генерируются последовательно, на создание одной секунды аудио уходит около 1—2 минут.


        Английский: пример


        Если убрать зависимость сети от входного текста и оставить только зависимость от предыдущей сгенерированной фонемы, то сеть будет генерировать подобные человеческому языку фонемы, но бессмысленные.


        Генерирование голоса: пример


        Эту же модель можно применить не только к речи, но и, например, к созданию музыки. Пример аудио, сгенерированного моделью, которую обучили на датасете игры на пианино (опять же без всякой зависимости от входных данных).


        Пример пианино


        Подробности — в статье.


        2.2. Чтение по губам


        Еще одна победа машинного обучения над человеком ;) На этот раз — в чтении по губам.


        Google Deepmind в сотрудничестве с Оксфордским университетом рассказывают в статье «Lip Reading Sentences in the Wild», как их модель, обученная на телевизионном датасете, смогла превзойти профессионального lips reader’а c канала BBC.


        image


        В датасете 100 тыс. предложений с аудио и видео. Модель: LSTM на аудио, CNN + LSTM на видео, эти два state-вектора подаются в итоговую LSTM, которая генерирует результат (characters).


        image


        При обучении использовались разные варианты входных данных: аудио, видео, аудио + видео, то есть модель «омниканальна».


        image


        2.3. Синтезируя Обаму: синхронизация движения губ с аудио


        image


        Университет Вашингтона проделал серьезную работу по генерированию движения губ бывшего президента США Обамы. Выбор пал на него в том числе из-за огромного количества записей его выступления в сети (17 часов HD-видео).


        Одной сетью обойтись не удалось, получалось слишком много артефактов. Поэтому авторы статьи сделали несколько костылей (или трюков, если угодно) по улучшению текстуры и таймингам.


        image


        Результат впечатляет. Скоро нельзя будет верить даже видео с президентом ;)


        3. Компьютерное зрение


        3.1. OCR: Google Maps и Street View


        В своих посте и статье команда Google Brain рассказывает, как внедрила в свои Карты новый движок OCR (Optical Character Recognition), с помощью которого распознаются указатели улиц и вывески магазинов.


        image


        image


        В процессе разработки технологии компания составила новый FSNS (French Street Name Signs), который содержит множество сложных кейсов.


        Сеть использует для распознавания каждого знака до четырех его фотографий. С помощью CNN извлекаются фичи, взвешиваются с помощью spatial attention (учитываются пиксельные координаты), а результат подается в LSTM.


        image


        Тот же самый подход авторы применяют к задаче распознавания названий магазинов на вывесках (там может быть много «шумовых» данных, и сеть сама должна «фокусироваться» в нужных местах). Алгоритм применили к 80 млрд фотографий.


        3.2. Visual Reasoning


        Существует такой тип задач, как Visual Reasoning, то есть нейросеть должна по фотографии ответить на какой-то вопрос. Например: «Есть ли на картинке резиновые вещи того же размера, что и желтый металлический цилиндр?» Вопрос и правда нетривиальный, и до недавнего времени задача решалась с точностью всего лишь 68,5 %.


        image


        И вновь прорыва добилась команда из Deepmind: на датасете CLEVR они достигли super-human точности в 95,5 %.


        Архитектура сети весьма интересная:


        1. По текстовому вопросу с помощью pretrained LSTM получаем embedding (представление) вопроса.
        2. По картинке с помощью CNN (всего четыре слоя) получаем feature maps (фичи, характеризующие картинку).
        3. Далее формируем попарные комбинации покоординатных slice’ов feature maps (желтые, синие, красные на картинке ниже), добавляем к каждой координаты и текстовый embedding.
        4. Прогоняем все эти тройки через еще одну сеть, суммируем.
        5. Полученное представление прогоняем через еще одну feedforward-сеть, которая уже на софтмаксе выдает ответ.


          image



        3.3. Pix2Code


        Интересное применение нейросетям придумала компания Uizard: по скриншоту от дизайнера интерфейсов генерировать код верстки.


        image


        Крайне полезное применение нейросетей, которое может облегчить жизнь при разработке софта. Авторы утверждают, что получили 77 % точности. Понятно, что это пока исследовательская работа и о боевом применении речи не идет.


        Кода и датасета в open source пока нет, но обещают выложить.





        3.4. SketchRNN: учим машину рисовать


        Возможно, вы видели страничку Quick, Draw! от Google с призывом нарисовать скетчи различных объектов за 20 секунд. Корпорация собирала этот датасет для того, чтобы обучить нейросеть рисовать, о чем Google рассказала в своем блоге и статье.


        image


        Собранный датасет состоит из 70 тыс. скетчей, он был в итоге выложен в открытый доступ. Скетчи представляют собой не картинки, а детализированные векторные представления рисунков (в какой точке пользователь нажал «карандаш», отпустил, куда провел линию и так далее).


        Исследователи обучили Sequence-to-Sequence Variational Autoencoder (VAE) c использованием RNN в качестве механизма кодирования/декодирования.


        image


        В итоге, как и положено автоенкодеру, модель получает латентный вектор, который характеризует исходную картинку.


        image


        Поскольку декодер умеет извлекать из этого вектора рисунок, то можно его менять и получать новые скетчи.


        image


        И даже выполнять векторную арифметику, чтобы соорудить котосвина:


        image


        3.5. GAN


        Одна из самых горячих тем в Deep Learning — Generative Adversarial Networks (GAN). Чаще всего эту идею используют для работы с изображениями, поэтому объясню концепцию именно на них.


        Суть идеи состоит в соревновании двух сетей — Генератора и Дискриминатора. Первая сеть создает картинку, а вторая пытается понять, реальная это картинка или сгенерированная.


        Схематично это выглядит так:


        image


        Во время обучения генератор из случайного вектора (шума) генерирует изображение и подает на вход дискриминатору, который говорит, фальшивка это или нет. Дискриминатору также подаются реальные изображения из датасета.


        Обучать такую конструкцию часто тяжело из-за того, что трудно найти точку равновесия двух сетей, чаще всего дискриминатор побеждает и обучение стагнирует. Однако преимущество системы в том, что мы можем решать задачи, в которых нам тяжело задать loss-функцию (например, улучшение качества фотографии), мы это отдаем на откуп дискриминатору.


        Классический пример результата обучения GAN — картинки спален или лиц.


        image


        image


        Ранее мы рассматривали автокодировщики (Sketch-RNN), которые кодируют исходные данные в латентное представление. С генератором получается то же самое.


        Очень наглядно идея генерирования изображения по вектору на примере лиц показана тут (можно изменять вектор и посмотреть, какие выходят лица).


        image


        Работает все та же арифметика над латентным пространством: «мужчина в очках» минус «мужчина» плюс «женщина» равно «женщина в очках».


        image


        3.6. Изменение возраста лица с помощью GAN


        Если при обучении подсунуть в латентный вектор контролируемый параметр, то при генерировании его можно менять и так управлять нужным образом на картинке. Этот подход именуется Conditional GAN.


        Так поступили авторы статьи «Face Aging With Conditional Generative Adversarial Networks». Обучив машину на датасете IMDB с известным возрастом актеров, исследователи получили возможность менять возраст лица.


        image


        3.7. Фотографии профессионального уровня


        В Google нашли еще одно интересное применение GAN — выбор и улучшение фотографий. GAN обучали на датасете профессиональных фотографий: генератор пытается улучшить плохие фотографии (профессионально снятые и ухудшенные с помощью специальных фильтров), а дискриминатор — различить «улучшенные» фотографии и реальные профессиональные.


        Обученный алгоритм прошелся по панорамам Google Street View в поиске лучших композиций и получил некоторые снимки профессионального и полупрофессионального качества (по оценкам фотографов).


        image


        image


        3.8. Синтезирование из текстового описания в изображение


        Впечатляющий пример использования GAN — генерирование картинок по тексту.


        image


        Авторы статьи предлагают подавать embedding текста на вход не только генератору (conditional GAN), но и дискриминатору, чтобы он проверял соответствие текста картинке. Чтобы дискриминатор научился выполнять свою функцию, дополнительно в обучение добавляли пары с неверным текстом для реальных картинок.


        image


        3.9. Pix2pix


        Одна из ярких статей конца 2016 года — «Image-to-Image Translation with Conditional Adversarial Networks» Berkeley AI Research (BAIR). Исследователи решали проблему image-to-image генерирования, когда, например, требуется по снимку со спутника создать карту или по наброску предметов — их реалистичную текстуру.


        image


        Это еще один пример успешной работы conditional GAN, в данном случае condition идет на целую картинку. В качестве архитектуры генератора использовалась UNet, популярная в сегментации изображений, а для борьбы с размытыми изображениями в качестве дискриминатора взяли новый классификатор PatchGAN (картинка нарезается на N патчей, и предсказание fake/real идет по каждому из них в отдельности).


        Авторы выпустили онлайн-демо своих сетей, что вызвало огромный интерес у пользователей.


        image


        Исходный код.


        3.10. CycleGAN


        Чтобы применить Pix2Pix, требуется датасет с соответствующими парами картинок из разных доменов. В случае, например, с картами собрать такой датасет не проблема. Но если хочется сделать что-то более сложное вроде «трансфигурирования» объектов или стилизации, то пар объектов не найти в принципе. Поэтому авторы Pix2Pix решили развить свою идею и придумали CycleGAN для трансфера между разными доменами изображений без конкретных пар — Unpaired Image-to-Image Translation.


        image


        Идея состоит в следующем: мы учим две пары генератор-дискриминатор из одного домена в другой и обратно, при этом мы требуем cycle consistency — после последовательного применения генераторов должно получиться изображение, похожее на исходное по L1 loss’у. Цикличный loss требуется для того, чтобы генератор не начал просто транслировать картинки одного домена в совершенно не связанные с исходным изображением.


        image


        Такой подход позволяет выучить маппинг лошади –> зебры.



        Такие трансформации работают нестабильно и часто создают неудачные варианты:


        image


        Исходный код.


        3.11. Разработка молекул в онкологии


        Машинное обучение сейчас приходит и в медицину. Помимо распознавания УЗИ, МРТ и диагностики его можно использовать для поиска новых лекарств для борьбы с раком.


        Мы уже подробно писали об этом исследовании тут, поэтому коротко: с помощью Adversarial Auto Encoder (AAE) можно выучить латентное представление молекул и дальше с его помощью искать новые. В результате нашли 69 молекул, половина из которых применяются для борьбы с раком, остальные имеют серьезный потенциал.


        image


        3.12. Adversarial-атаки


        Сейчас активно исследуется тема с adversarial-атаками. Что это такое? Стандартные сети, обучаемые, например, на ImageNet, совершенно неустойчивы к добавлению специального шума к классифицируемой картинке. На примере ниже мы видим, что картинка с шумом для человеческого глаза практически не меняется, однако модель сходит с ума и предсказывает совершенно иной класс.


        image


        Устойчивость достигается с помощью, например, Fast Gradient Sign Method (FGSM): имея доступ к параметрам модели, можно сделать один или несколько градиентных шагов в сторону нужного класса и изменить исходную картинку.


        Одна из задач на Kaggle к грядущему NIPS как раз связана с этим: участникам предлагается создать универсальные атаки/защиты, которые в итоге запускаются все против всех для определения лучших.


        Зачем нам вообще исследовать эти атаки? Во-первых, если мы хотим защитить свои продукты, то можно добавлять к капче шум, чтобы мешать спамерам распознавать ее автоматом. Во-вторых, алгоритмы все больше и больше участвуют в нашей жизни — системы распознавания лиц, беспилотные автомобили. При этом злоумышленники могут использовать недостатки алгоритмов. Вот пример, когда специальные очки позволяют обмануть систему распознавания лиц и «представиться» другим человеком. Так что модели надо будет учить с учетом возможных атак.


        image


        Такие манипуляции со знаками тоже не позволяют правильно их распознать.


        image


        Набор статей от организаторов конкурса.


        Уже написанные библиотеки для атак: cleverhans и foolbox.


        4. Обучение с подкреплением


        Reinforcement learning (RL), или обучение с подкреплением, — также сейчас одна из интереснейших и активно развивающихся тем в машинном обучении.


        Суть подхода заключается в выучивании успешного поведения агента в среде, которая при взаимодействии дает обратную связь (reward). В общем, через опыт — так же, как учатся люди в течение жизни.


        image


        RL активно применяют в играх, роботах, управлении системами (трафиком, например).


        Разумеется, все слышали о победах AlphaGo от DeepMind в игре го над лучшими профессионалами. Статья авторов была опубликована в Nature «Mastering the game of Go». При обучении разработчики использовали RL: бот играл сам с собой для совершенствования своих стратегий.


        4.1. Обучение с подкреплением с неконтролируемыми вспомогательными задачами


        В предыдущие годы DeepMind научился с помощью DQN играть в аркадные игры лучше человека. Сейчас алгоритмы учат играть в более сложные игры типа Doom.


        Много внимания уделено ускорению обучения, потому что наработка опыта агента во взаимодействии со средой требует многих часов обучения на современных GPU.


        Deepmind в своем блоге рассказывает о том, что введение дополнительных loss’ов (auxiliary tasks, вспомогательных задач), таких как предсказание изменения кадра (pixel control), чтобы агент лучше понимал последствия действий, существенно ускоряет обучение.



        Результаты обучения:





        4.2. Обучающиеся роботы


        В OpenAI активно исследуют обучение человеком агента в виртуальной среде, что более безопасно для экспериментов, чем в реальной жизни ;)


        В одном из исследований команда показала, что one-shot learning возможно: человек показывает в VR, как выполнить определенную задачу, и алгоритму достаточно одной демонстрации, чтобы выучить ее и далее воспроизвести в реальных условиях.


        image


        Эх, если бы с людьми было так просто ;)


        4.3. Обучение на человеческих предпочтениях


        Работа OpenAI и DeepMind на ту же тему. Суть состоит в следующем: у агента есть некая задача, алгоритм предоставляет на суд человеку два возможных варианта решения, и человек указывает, какой лучше. Процесс повторяется итеративно, и алгоритм за 900 бит обратной связи (бинарной разметки) от человека выучился решать задачу.


        image



        Как всегда, человеку надо быть осторожным и думать, чему он учит машину. Например, оценщик решил, что алгоритм действительно хотел взять объект, но на самом деле тот лишь имитировал это действие.


        image


        4.4. Движение в сложных окружениях


        Еще одно исследование от DeepMind. Чтобы научить робота сложному поведению (ходить/прыгать/...), да еще и похожему на человеческое, нужно сильно заморочиться с выбором функции потерь, которая будет поощрять нужное поведение. Но хотелось бы, чтобы алгоритм сам выучивал сложное поведение, опираясь на простые reward.


        Исследователям удалось этого добиться: они научили агентов (эмуляторы тел) совершать сложные действия с помощью конструирования сложной среды с препятствиями и с простым reward за прогресс в передвижении.


        image


        Впечатляющее видео с результатами. Но оно гораздо забавнее с наложенным звуком ;)







        Напоследок дам ссылку на опубликованные недавно алгоритмы обучения RL от OpenAI. Теперь можно использовать более современные решения, чем уже ставший стандартным DQN.


        5. Прочее


        5.1. Охлаждение дата-центра


        В июле 2017-го Google рассказала, что воспользовалась разработками DeepMind в машинном обучении, чтобы сократить энергозатраты своего дата-центра.


        На основе информации с тысяч датчиков в дата-центре разработчики Google натренировали ансамбль нейросетей для предсказания PUE (Power Usage Effectiveness) и более эффективного управления дата-центром. Это впечатляющий и значимый пример практического применения ML.


        image


        5.2. Одна модель на все задачи


        Как вы знаете, обученные модели плохо переносятся от задачи к задаче, под каждую задачу приходится обучать/дообучать специфичную модель. Небольшой шаг в сторону универсальности моделей сделала Google Brain в своей статье «One Model To Learn Them All».


        Исследователи обучили модель, которая выполняет восемь задач из разных доменов (текст, речь, изображения). Например, перевод с разных языков, парсинг текста, распознавание изображений и звука.


        image


        Для достижения этой цели сделали сложную архитектуру сети с различными блоками для обработки разных входных данных и генерирования результата. Блоки для encoder/decoder делятся на три типа: сверточные, attention, gated mixture of experts (MoE).


        image


        image


        Основные итоги обучения:


        • получились почти совершенные модели (авторы не делали тонкой настройки гиперпараметров);
        • происходит передача знаний между разными доменами, то есть на задачах с большим количеством данных производительность будет почти такой же. А на маленьких задачах (например, на парсинге) — лучше;
        • блоки, нужные для разных задач, не мешают друг другу и даже иногда помогают, например, MoE — для Imagenet-задачи.

        Кстати, эта модель есть в tensor2tensor.


        5.3. Обучение на Imagenet за один час


        В своем посте сотрудники Facebook рассказали, как их инженеры смогли добиться обучения модели Resnet-50 на Imagenet всего за один час. Правда, для этого потребовался кластер из 256 GPU (Tesla P100).


        Для распределенного обучения использовали Gloo и Caffe2. Чтобы процесс шел эффективно, пришлось адаптировать стратегию обучения при огромном батче (8192 элемента): усреднение градиентов, фаза прогрева, специальные learning rate и тому подобное. Подробнее в статье.


        В итоге удалось добиться эффективности 90% при масштабировании от 8 к 256 GPU. Теперь исследователи из Facebook могут экспериментировать еще быстрее, в отличие от простых смертных без такого кластера ;)


        6. Новости


        6.1. Беспилотные автомобили


        Сфера беспилотных автомобилей интенсивно развивается, и машины активно тестируют в боевых условиях. Из относительно недавних событий можно отметить покупку Intel’ом MobilEye, скандал вокруг Uber и украденных экс-сотрудником Google технологий, первую смерть при работе автопилота и многое другое.


        Отмечу один момент: Google Waymo запускает бета-программу. Google — пионер в этой области, и предполагается, что их технология очень хороша, ведь машины наездили уже более 3 млн миль.


        Также совсем недавно беспилотным автомобилям разрешили колесить по всем штатам США.


        6.2. Здравоохранение


        Как я уже говорил, современный ML начинает внедряться в медицину. Например, Google сотрудничает с медицинским центром для помощи диагностам.


        image


        Deepmind создал даже отдельное подразделение.


        image


        В этом году в рамках Data Science Bowl был проведен конкурс по предсказанию рака легких через год на основе подробных снимков, призовой фонд — один миллион долларов.


        6.3. Инвестиции


        Сейчас много и усердно инвестируют в ML, как до этого — в BigData.


        КНР вкладывает 150 млрд долларов в AI, чтобы стать мировым лидером индустрии.


        Для сравнения, в Baidu Research работает 1300 человек, а в том же FAIR (Facebook) — 80. На последнем KDD сотрудники Alibaba рассказывали про свой parameter server KungPeng, который работает на 100 миллиардных выборках при триллионе параметров, что «становится обычной задачей» (с).


        image




        Делайте выводы, изучайте ML. Так или иначе со временем все разработчики будут использовать машинное обучение, что станет одной из компетенций, как сегодня — умение работать с базами данных.

        Original source: habrahabr.ru (comments, light).

        https://habrahabr.ru/post/338248/


        Метки:  

        Достижения в глубоком обучении за последний год

        Четверг, 21 Сентября 2017 г. 17:28 + в цитатник
        EdT сегодня в 17:28 Разработка

        Достижения в глубоком обучении за последний год


          Привет, Хабр. В своей статье я расскажу вам, что интересного произошло в мире машинного обучения за последний год (в основном в Deep Learning). А произошло очень многое, поэтому я остановился на самых, на мой взгляд, зрелищных и/или значимых достижениях. Технические аспекты улучшения архитектур сетей в статье не приводятся. Расширяем кругозор!


          1. Текст


          1.1. Google Neural Machine Translation


          Почти год назад Google анонсировала запуск новой модели для Google Translate. Компания подробно описала архитектуру сети — Recurrent Neural Network (RNN) — в своей статье.



          Основной результат: сокращение отставания от человека по точности перевода на 55—85 % (оценивали люди по 6-балльной шкале). Воспроизвести высокие результаты этой модели сложно без огромного датасета, который имеется у Google.


          image


          2.1. Переговоры. Будет сделка?


          Вы могли слышать дурацкие новости о том, что Facebook выключила своего чат-бота, который вышел из-под контроля и выдумал свой язык. Этого чат-бота компания создала для переговоров. Его цель — вести текстовые переговоры с другим агентом и достичь сделки: как разделить на двоих предметы (книги, шляпы...). У каждого агента своя цель в переговорах, другой ее не знает. Просто уйти с переговоров без сделки нельзя.


          Для обучения собрали датасет человеческих переговоров, обучили supervised рекуррентную сеть, далее уже обученного агента с помощью reinforcement learning (обучения с подкреплением) тренировали переговариваться с самим собой, поставив ограничение: похожесть языка на человеческий.


          Бот научился одной из стратегий реальных переговоров — показывать поддельный интерес к некоторым аспектам сделки, чтобы потом по ним уступить, получив выгоду по своим настоящим целям. Это первая попытка создания подобного переговорного бота, и довольно удачная.


          image


          Подробности — в статье, код выложен в открытый доступ.


          Разумеется, новость о том, что бот якобы придумал язык, раздули на пустом месте. При обучении (при переговорах с таким же агентом) отключили ограничение похожести текста на человеческий, и алгоритм модифицировал язык взаимодействия. Ничего необычного.




          За последний год рекуррентные сети активно развивали и использовали во многих задачах и приложениях. Архитектуры рекуррентных сетей сильно усложнились, однако по некоторым направлениям похожих результатов достигают и простые feedforward-сети — DSSM. Например, Google для своей почтовой фичи Smart Reply достигла такого же качества, как и с LSTM до этого. А Яндекс запустил новый поисковый движок на основе таких сетей.


          2. Речь


          2.1. WaveNet: генерирующая модель для необработанного аудио


          Сотрудники DeepMind (компания, известная своим ботом для игры в го, ныне принадлежащая Google) рассказали в своей статье про генерирование аудио.


          Если коротко, то исследователи сделали авторегрессионную полносверточную модель WaveNet на основе предыдущих подходов к генерированию изображений (PixelRNN и PixelCNN).



          Сеть обучалась end-to-end: на вход текст, на выход аудио. Результат превосходный, разница с человеком сократилась на 50 %.


          image


          Основной недостаток сети — низкая производительность, потому что из-за авторегрессии звуки генерируются последовательно, на создание одной секунды аудио уходит около 1—2 минут.


          Английский: пример


          Если убрать зависимость сети от входного текста и оставить только зависимость от предыдущей сгенерированной фонемы, то сеть будет генерировать подобные человеческому языку фонемы, но бессмысленные.


          Генерирование голоса: пример


          Эту же модель можно применить не только к речи, но и, например, к созданию музыки. Пример аудио, сгенерированного моделью, которую обучили на датасете игры на пианино (опять же без всякой зависимости от входных данных).


          Пример пианино


          Подробности — в статье.


          2.2. Чтение по губам


          Еще одна победа машинного обучения над человеком ;) На этот раз — в чтении по губам.


          Google Deepmind в сотрудничестве с Оксфордским университетом рассказывают в статье «Lip Reading Sentences in the Wild», как их модель, обученная на телевизионном датасете, смогла превзойти профессионального lips reader’а c канала BBC.


          image


          В датасете 100 тыс. предложений с аудио и видео. Модель: LSTM на аудио, CNN + LSTM на видео, эти два state-вектора подаются в итоговую LSTM, которая генерирует результат (characters).


          image


          При обучении использовались разные варианты входных данных: аудио, видео, аудио + видео, то есть модель «омниканальна».


          image


          2.3. Синтезируя Обаму: синхронизация движения губ с аудио


          image


          Университет Вашингтона проделал серьезную работу по генерированию движения губ бывшего президента США Обамы. Выбор пал на него в том числе из-за огромного количества записей его выступления в сети (17 часов HD-видео).


          Одной сетью обойтись не удалось, получалось слишком много артефактов. Поэтому авторы статьи сделали несколько костылей (или трюков, если угодно) по улучшению текстуры и таймингам.


          image


          Результат впечатляет. Скоро нельзя будет верить даже видео с президентом ;)


          3. Компьютерное зрение


          3.1. OCR: Google Maps и Street View


          В своих посте и статье команда Google Brain рассказывает, как внедрила в свои Карты новый движок OCR (Optical Character Recognition), с помощью которого распознаются указатели улиц и вывески магазинов.


          image


          image


          В процессе разработки технологии компания составила новый FSNS (French Street Name Signs), который содержит множество сложных кейсов.


          Сеть использует для распознавания каждого знака до четырех его фотографий. С помощью CNN извлекаются фичи, взвешиваются с помощью spatial attention (учитываются пиксельные координаты), а результат подается в LSTM.


          image


          Тот же самый подход авторы применяют к задаче распознавания названий магазинов на вывесках (там может быть много «шумовых» данных, и сеть сама должна «фокусироваться» в нужных местах). Алгоритм применили к 80 млрд фотографий.


          3.2. Visual Reasoning


          Существует такой тип задач, как Visual Reasoning, то есть нейросеть должна по фотографии ответить на какой-то вопрос. Например: «Есть ли на картинке резиновые вещи того же размера, что и желтый металлический цилиндр?» Вопрос и правда нетривиальный, и до недавнего времени задача решалась с точностью всего лишь 68,5 %.


          image


          И вновь прорыва добилась команда из Deepmind: на датасете CLEVR они достигли super-human точности в 95,5 %.


          Архитектура сети весьма интересная:


          1. По текстовому вопросу с помощью pretrained LSTM получаем embedding (представление) вопроса.
          2. По картинке с помощью CNN (всего четыре слоя) получаем feature maps (фичи, характеризующие картинку).
          3. Далее формируем попарные комбинации покоординатных slice’ов feature maps (желтые, синие, красные на картинке ниже), добавляем к каждой координаты и текстовый embedding.
          4. Прогоняем все эти тройки через еще одну сеть, суммируем.
          5. Полученное представление прогоняем через еще одну feedforward-сеть, которая уже на софтмаксе выдает ответ.


            image



          3.3. Pix2Code


          Интересное применение нейросетям придумала компания Uizard: по скриншоту от дизайнера интерфейсов генерировать код верстки.


          image


          Крайне полезное применение нейросетей, которое может облегчить жизнь при разработке софта. Авторы утверждают, что получили 77 % точности. Понятно, что это пока исследовательская работа и о боевом применении речи не идет.


          Кода и датасета в open source пока нет, но обещают выложить.





          3.4. SketchRNN: учим машину рисовать


          Возможно, вы видели страничку Quick, Draw! от Google с призывом нарисовать скетчи различных объектов за 20 секунд. Корпорация собирала этот датасет для того, чтобы обучить нейросеть рисовать, о чем Google рассказала в своем блоге и статье.


          image


          Собранный датасет состоит из 70 тыс. скетчей, он был в итоге выложен в открытый доступ. Скетчи представляют собой не картинки, а детализированные векторные представления рисунков (в какой точке пользователь нажал «карандаш», отпустил, куда провел линию и так далее).


          Исследователи обучили Sequence-to-Sequence Variational Autoencoder (VAE) c использованием RNN в качестве механизма кодирования/декодирования.


          image


          В итоге, как и положено автоенкодеру, модель получает латентный вектор, который характеризует исходную картинку.


          image


          Поскольку декодер умеет извлекать из этого вектора рисунок, то можно его менять и получать новые скетчи.


          image


          И даже выполнять векторную арифметику, чтобы соорудить котосвина:


          image


          3.5. GAN


          Одна из самых горячих тем в Deep Learning — Generative Adversarial Networks (GAN). Чаще всего эту идею используют для работы с изображениями, поэтому объясню концепцию именно на них.


          Суть идеи состоит в соревновании двух сетей — Генератора и Дискриминатора. Первая сеть создает картинку, а вторая пытается понять, реальная это картинка или сгенерированная.


          Схематично это выглядит так:


          image


          Во время обучения генератор из случайного вектора (шума) генерирует изображение и подает на вход дискриминатору, который говорит, фальшивка это или нет. Дискриминатору также подаются реальные изображения из датасета.


          Обучать такую конструкцию часто тяжело из-за того, что трудно найти точку равновесия двух сетей, чаще всего дискриминатор побеждает и обучение стагнирует. Однако преимущество системы в том, что мы можем решать задачи, в которых нам тяжело задать loss-функцию (например, улучшение качества фотографии), мы это отдаем на откуп дискриминатору.


          Классический пример результата обучения GAN — картинки спален или лиц.


          image


          image


          Ранее мы рассматривали автокодировщики (Sketch-RNN), которые кодируют исходные данные в латентное представление. С генератором получается то же самое.


          Очень наглядно идея генерирования изображения по вектору на примере лиц показана тут (можно изменять вектор и посмотреть, какие выходят лица).


          image


          Работает все та же арифметика над латентным пространством: «мужчина в очках» минус «мужчина» плюс «женщина» равно «женщина в очках».


          image


          3.6. Изменение возраста лица с помощью GAN


          Если при обучении подсунуть в латентный вектор контролируемый параметр, то при генерировании его можно менять и так управлять нужным образом на картинке. Этот подход именуется Conditional GAN.


          Так поступили авторы статьи «Face Aging With Conditional Generative Adversarial Networks». Обучив машину на датасете IMDB с известным возрастом актеров, исследователи получили возможность менять возраст лица.


          image


          3.7. Фотографии профессионального уровня


          В Google нашли еще одно интересное применение GAN — выбор и улучшение фотографий. GAN обучали на датасете профессиональных фотографий: генератор пытается улучшить плохие фотографии (профессионально снятые и ухудшенные с помощью специальных фильтров), а дискриминатор — различить «улучшенные» фотографии и реальные профессиональные.


          Обученный алгоритм прошелся по панорамам Google Street View в поиске лучших композиций и получил некоторые снимки профессионального и полупрофессионального качества (по оценкам фотографов).


          image


          image


          3.8. Синтезирование из текстового описания в изображение


          Впечатляющий пример использования GAN — генерирование картинок по тексту.


          image


          Авторы статьи предлагают подавать embedding текста на вход не только генератору (conditional GAN), но и дискриминатору, чтобы он проверял соответствие текста картинке. Чтобы дискриминатор научился выполнять свою функцию, дополнительно в обучение добавляли пары с неверным текстом для реальных картинок.


          image


          3.9. Pix2pix


          Одна из ярких статей конца 2016 года — «Image-to-Image Translation with Conditional Adversarial Networks» Berkeley AI Research (BAIR). Исследователи решали проблему image-to-image генерирования, когда, например, требуется по снимку со спутника создать карту или по наброску предметов — их реалистичную текстуру.


          image


          Это еще один пример успешной работы conditional GAN, в данном случае condition идет на целую картинку. В качестве архитектуры генератора использовалась UNet, популярная в сегментации изображений, а для борьбы с размытыми изображениями в качестве дискриминатора взяли новый классификатор PatchGAN (картинка нарезается на N патчей, и предсказание fake/real идет по каждому из них в отдельности).


          Авторы выпустили онлайн-демо своих сетей, что вызвало огромный интерес у пользователей.


          image


          Исходный код.


          3.10. CycleGAN


          Чтобы применить Pix2Pix, требуется датасет с соответствующими парами картинок из разных доменов. В случае, например, с картами собрать такой датасет не проблема. Но если хочется сделать что-то более сложное вроде «трансфигурирования» объектов или стилизации, то пар объектов не найти в принципе. Поэтому авторы Pix2Pix решили развить свою идею и придумали CycleGAN для трансфера между разными доменами изображений без конкретных пар — Unpaired Image-to-Image Translation.


          image


          Идея состоит в следующем: мы учим две пары генератор-дискриминатор из одного домена в другой и обратно, при этом мы требуем cycle consistency — после последовательного применения генераторов должно получиться изображение, похожее на исходное по L1 loss’у. Цикличный loss требуется для того, чтобы генератор не начал просто транслировать картинки одного домена в совершенно не связанные с исходным изображением.


          image


          Такой подход позволяет выучить маппинг лошади –> зебры.



          Такие трансформации работают нестабильно и часто создают неудачные варианты:


          image


          Исходный код.


          3.11. Разработка молекул в онкологии


          Машинное обучение сейчас приходит и в медицину. Помимо распознавания УЗИ, МРТ и диагностики его можно использовать для поиска новых лекарств для борьбы с раком.


          Мы уже подробно писали об этом исследовании тут, поэтому коротко: с помощью Adversarial Auto Encoder (AAE) можно выучить латентное представление молекул и дальше с его помощью искать новые. В результате нашли 69 молекул, половина из которых применяются для борьбы с раком, остальные имеют серьезный потенциал.


          image


          3.12. Adversarial-атаки


          Сейчас активно исследуется тема с adversarial-атаками. Что это такое? Стандартные сети, обучаемые, например, на ImageNet, совершенно неустойчивы к добавлению специального шума к классифицируемой картинке. На примере ниже мы видим, что картинка с шумом для человеческого глаза практически не меняется, однако модель сходит с ума и предсказывает совершенно иной класс.


          image


          Устойчивость достигается с помощью, например, Fast Gradient Sign Method (FGSM): имея доступ к параметрам модели, можно сделать один или несколько градиентных шагов в сторону нужного класса и изменить исходную картинку.


          Одна из задач на Kaggle к грядущему NIPS как раз связана с этим: участникам предлагается создать универсальные атаки/защиты, которые в итоге запускаются все против всех для определения лучших.


          Зачем нам вообще исследовать эти атаки? Во-первых, если мы хотим защитить свои продукты, то можно добавлять к капче шум, чтобы мешать спамерам распознавать ее автоматом. Во-вторых, алгоритмы все больше и больше участвуют в нашей жизни — системы распознавания лиц, беспилотные автомобили. При этом злоумышленники могут использовать недостатки алгоритмов. Вот пример, когда специальные очки позволяют обмануть систему распознавания лиц и «представиться» другим человеком. Так что модели надо будет учить с учетом возможных атак.


          image


          Такие манипуляции со знаками тоже не позволяют правильно их распознать.


          image


          Набор статей от организаторов конкурса.


          Уже написанные библиотеки для атак: cleverhans и foolbox.


          4. Обучение с подкреплением


          Reinforcement learning (RL), или обучение с подкреплением, — также сейчас одна из интереснейших и активно развивающихся тем в машинном обучении.


          Суть подхода заключается в выучивании успешного поведения агента в среде, которая при взаимодействии дает обратную связь (reward). В общем, через опыт — так же, как учатся люди в течение жизни.


          image


          RL активно применяют в играх, роботах, управлении системами (трафиком, например).


          Разумеется, все слышали о победах AlphaGo от DeepMind в игре го над лучшими профессионалами. Статья авторов была опубликована в Nature «Mastering the game of Go». При обучении разработчики использовали RL: бот играл сам с собой для совершенствования своих стратегий.


          4.1. Обучение с подкреплением с неконтролируемыми вспомогательными задачами


          В предыдущие годы DeepMind научился с помощью DQN играть в аркадные игры лучше человека. Сейчас алгоритмы учат играть в более сложные игры типа Doom.


          Много внимания уделено ускорению обучения, потому что наработка опыта агента во взаимодействии со средой требует многих часов обучения на современных GPU.


          Deepmind в своем блоге рассказывает о том, что введение дополнительных loss’ов (auxiliary tasks, вспомогательных задач), таких как предсказание изменения кадра (pixel control), чтобы агент лучше понимал последствия действий, существенно ускоряет обучение.



          Результаты обучения:





          4.2. Обучающиеся роботы


          В OpenAI активно исследуют обучение человеком агента в виртуальной среде, что более безопасно для экспериментов, чем в реальной жизни ;)


          В одном из исследований команда показала, что one-shot learning возможно: человек показывает в VR, как выполнить определенную задачу, и алгоритму достаточно одной демонстрации, чтобы выучить ее и далее воспроизвести в реальных условиях.


          image


          Эх, если бы с людьми было так просто ;)


          4.3. Обучение на человеческих предпочтениях


          Работа OpenAI и DeepMind на ту же тему. Суть состоит в следующем: у агента есть некая задача, алгоритм предоставляет на суд человеку два возможных варианта решения, и человек указывает, какой лучше. Процесс повторяется итеративно, и алгоритм за 900 бит обратной связи (бинарной разметки) от человека выучился решать задачу.


          image



          Как всегда, человеку надо быть осторожным и думать, чему он учит машину. Например, оценщик решил, что алгоритм действительно хотел взять объект, но на самом деле тот лишь имитировал это действие.


          image


          4.4. Движение в сложных окружениях


          Еще одно исследование от DeepMind. Чтобы научить робота сложному поведению (ходить/прыгать/...), да еще и похожему на человеческое, нужно сильно заморочиться с выбором функции потерь, которая будет поощрять нужное поведение. Но хотелось бы, чтобы алгоритм сам выучивал сложное поведение, опираясь на простые reward.


          Исследователям удалось этого добиться: они научили агентов (эмуляторы тел) совершать сложные действия с помощью конструирования сложной среды с препятствиями и с простым reward за прогресс в передвижении.


          image


          Впечатляющее видео с результатами. Но оно гораздо забавнее с наложенным звуком ;)







          Напоследок дам ссылку на опубликованные недавно алгоритмы обучения RL от OpenAI. Теперь можно использовать более современные решения, чем уже ставший стандартным DQN.


          5. Прочее


          5.1. Охлаждение дата-центра


          В июле 2017-го Google рассказала, что воспользовалась разработками DeepMind в машинном обучении, чтобы сократить энергозатраты своего дата-центра.


          На основе информации с тысяч датчиков в дата-центре разработчики Google натренировали ансамбль нейросетей для предсказания PUE (Power Usage Effectiveness) и более эффективного управления дата-центром. Это впечатляющий и значимый пример практического применения ML.


          image


          5.2. Одна модель на все задачи


          Как вы знаете, обученные модели плохо переносятся от задачи к задаче, под каждую задачу приходится обучать/дообучать специфичную модель. Небольшой шаг в сторону универсальности моделей сделала Google Brain в своей статье «One Model To Learn Them All».


          Исследователи обучили модель, которая выполняет восемь задач из разных доменов (текст, речь, изображения). Например, перевод с разных языков, парсинг текста, распознавание изображений и звука.


          image


          Для достижения этой цели сделали сложную архитектуру сети с различными блоками для обработки разных входных данных и генерирования результата. Блоки для encoder/decoder делятся на три типа: сверточные, attention, gated mixture of experts (MoE).


          image


          image


          Основные итоги обучения:


          • получились почти совершенные модели (авторы не делали тонкой настройки гиперпараметров);
          • происходит передача знаний между разными доменами, то есть на задачах с большим количеством данных производительность будет почти такой же. А на маленьких задачах (например, на парсинге) — лучше;
          • блоки, нужные для разных задач, не мешают друг другу и даже иногда помогают, например, MoE — для Imagenet-задачи.

          Кстати, эта модель есть в tensor2tensor.


          5.3. Обучение на Imagenet за один час


          В своем посте сотрудники Facebook рассказали, как их инженеры смогли добиться обучения модели Resnet-50 на Imagenet всего за один час. Правда, для этого потребовался кластер из 256 GPU (Tesla P100).


          Для распределенного обучения использовали Gloo и Caffe2. Чтобы процесс шел эффективно, пришлось адаптировать стратегию обучения при огромном батче (8192 элемента): усреднение градиентов, фаза прогрева, специальные learning rate и тому подобное. Подробнее в статье.


          В итоге удалось добиться эффективности 90% при масштабировании от 8 к 256 GPU. Теперь исследователи из Facebook могут экспериментировать еще быстрее, в отличие от простых смертных без такого кластера ;)


          6. Новости


          6.1. Беспилотные автомобили


          Сфера беспилотных автомобилей интенсивно развивается, и машины активно тестируют в боевых условиях. Из относительно недавних событий можно отметить покупку Intel’ом MobilEye, скандал вокруг Uber и украденных экс-сотрудником Google технологий, первую смерть при работе автопилота и многое другое.


          Отмечу один момент: Google Waymo запускает бета-программу. Google — пионер в этой области, и предполагается, что их технология очень хороша, ведь машины наездили уже более 3 млн миль.


          Также совсем недавно беспилотным автомобилям разрешили колесить по всем штатам США.


          6.2. Здравоохранение


          Как я уже говорил, современный ML начинает внедряться в медицину. Например, Google сотрудничает с медицинским центром для помощи диагностам.


          image


          Deepmind создал даже отдельное подразделение.


          image


          В этом году в рамках Data Science Bowl был проведен конкурс по предсказанию рака легких через год на основе подробных снимков, призовой фонд — один миллион долларов.


          6.3. Инвестиции


          Сейчас много и усердно инвестируют в ML, как до этого — в BigData.


          КНР вкладывает 150 млрд долларов в AI, чтобы стать мировым лидером индустрии.


          Для сравнения, в Baidu Research работает 1300 человек, а в том же FAIR (Facebook) — 80. На последнем KDD сотрудники Alibaba рассказывали про свой parameter server KungPeng, который работает на 100 миллиардных выборках при триллионе параметров, что «становится обычной задачей» (с).


          image




          Делайте выводы, изучайте ML. Так или иначе со временем все разработчики будут использовать машинное обучение, что станет одной из компетенций, как сегодня — умение работать с базами данных.

          Original source: habrahabr.ru (comments, light).

          https://habrahabr.ru/post/338248/


          Метки:  

          Достижения в глубоком обучении за последний год

          Четверг, 21 Сентября 2017 г. 17:28 + в цитатник
          EdT сегодня в 17:28 Разработка

          Достижения в глубоком обучении за последний год


            Привет, Хабр. В своей статье я расскажу вам, что интересного произошло в мире машинного обучения за последний год (в основном в Deep Learning). А произошло очень многое, поэтому я остановился на самых, на мой взгляд, зрелищных и/или значимых достижениях. Технические аспекты улучшения архитектур сетей в статье не приводятся. Расширяем кругозор!


            1. Текст


            1.1. Google Neural Machine Translation


            Почти год назад Google анонсировала запуск новой модели для Google Translate. Компания подробно описала архитектуру сети — Recurrent Neural Network (RNN) — в своей статье.



            Основной результат: сокращение отставания от человека по точности перевода на 55—85 % (оценивали люди по 6-балльной шкале). Воспроизвести высокие результаты этой модели сложно без огромного датасета, который имеется у Google.


            image


            2.1. Переговоры. Будет сделка?


            Вы могли слышать дурацкие новости о том, что Facebook выключила своего чат-бота, который вышел из-под контроля и выдумал свой язык. Этого чат-бота компания создала для переговоров. Его цель — вести текстовые переговоры с другим агентом и достичь сделки: как разделить на двоих предметы (книги, шляпы...). У каждого агента своя цель в переговорах, другой ее не знает. Просто уйти с переговоров без сделки нельзя.


            Для обучения собрали датасет человеческих переговоров, обучили supervised рекуррентную сеть, далее уже обученного агента с помощью reinforcement learning (обучения с подкреплением) тренировали переговариваться с самим собой, поставив ограничение: похожесть языка на человеческий.


            Бот научился одной из стратегий реальных переговоров — показывать поддельный интерес к некоторым аспектам сделки, чтобы потом по ним уступить, получив выгоду по своим настоящим целям. Это первая попытка создания подобного переговорного бота, и довольно удачная.


            image


            Подробности — в статье, код выложен в открытый доступ.


            Разумеется, новость о том, что бот якобы придумал язык, раздули на пустом месте. При обучении (при переговорах с таким же агентом) отключили ограничение похожести текста на человеческий, и алгоритм модифицировал язык взаимодействия. Ничего необычного.




            За последний год рекуррентные сети активно развивали и использовали во многих задачах и приложениях. Архитектуры рекуррентных сетей сильно усложнились, однако по некоторым направлениям похожих результатов достигают и простые feedforward-сети — DSSM. Например, Google для своей почтовой фичи Smart Reply достигла такого же качества, как и с LSTM до этого. А Яндекс запустил новый поисковый движок на основе таких сетей.


            2. Речь


            2.1. WaveNet: генерирующая модель для необработанного аудио


            Сотрудники DeepMind (компания, известная своим ботом для игры в го, ныне принадлежащая Google) рассказали в своей статье про генерирование аудио.


            Если коротко, то исследователи сделали авторегрессионную полносверточную модель WaveNet на основе предыдущих подходов к генерированию изображений (PixelRNN и PixelCNN).



            Сеть обучалась end-to-end: на вход текст, на выход аудио. Результат превосходный, разница с человеком сократилась на 50 %.


            image


            Основной недостаток сети — низкая производительность, потому что из-за авторегрессии звуки генерируются последовательно, на создание одной секунды аудио уходит около 1—2 минут.


            Английский: пример


            Если убрать зависимость сети от входного текста и оставить только зависимость от предыдущей сгенерированной фонемы, то сеть будет генерировать подобные человеческому языку фонемы, но бессмысленные.


            Генерирование голоса: пример


            Эту же модель можно применить не только к речи, но и, например, к созданию музыки. Пример аудио, сгенерированного моделью, которую обучили на датасете игры на пианино (опять же без всякой зависимости от входных данных).


            Пример пианино


            Подробности — в статье.


            2.2. Чтение по губам


            Еще одна победа машинного обучения над человеком ;) На этот раз — в чтении по губам.


            Google Deepmind в сотрудничестве с Оксфордским университетом рассказывают в статье «Lip Reading Sentences in the Wild», как их модель, обученная на телевизионном датасете, смогла превзойти профессионального lips reader’а c канала BBC.


            image


            В датасете 100 тыс. предложений с аудио и видео. Модель: LSTM на аудио, CNN + LSTM на видео, эти два state-вектора подаются в итоговую LSTM, которая генерирует результат (characters).


            image


            При обучении использовались разные варианты входных данных: аудио, видео, аудио + видео, то есть модель «омниканальна».


            image


            2.3. Синтезируя Обаму: синхронизация движения губ с аудио


            image


            Университет Вашингтона проделал серьезную работу по генерированию движения губ бывшего президента США Обамы. Выбор пал на него в том числе из-за огромного количества записей его выступления в сети (17 часов HD-видео).


            Одной сетью обойтись не удалось, получалось слишком много артефактов. Поэтому авторы статьи сделали несколько костылей (или трюков, если угодно) по улучшению текстуры и таймингам.


            image


            Результат впечатляет. Скоро нельзя будет верить даже видео с президентом ;)


            3. Компьютерное зрение


            3.1. OCR: Google Maps и Street View


            В своих посте и статье команда Google Brain рассказывает, как внедрила в свои Карты новый движок OCR (Optical Character Recognition), с помощью которого распознаются указатели улиц и вывески магазинов.


            image


            image


            В процессе разработки технологии компания составила новый FSNS (French Street Name Signs), который содержит множество сложных кейсов.


            Сеть использует для распознавания каждого знака до четырех его фотографий. С помощью CNN извлекаются фичи, взвешиваются с помощью spatial attention (учитываются пиксельные координаты), а результат подается в LSTM.


            image


            Тот же самый подход авторы применяют к задаче распознавания названий магазинов на вывесках (там может быть много «шумовых» данных, и сеть сама должна «фокусироваться» в нужных местах). Алгоритм применили к 80 млрд фотографий.


            3.2. Visual Reasoning


            Существует такой тип задач, как Visual Reasoning, то есть нейросеть должна по фотографии ответить на какой-то вопрос. Например: «Есть ли на картинке резиновые вещи того же размера, что и желтый металлический цилиндр?» Вопрос и правда нетривиальный, и до недавнего времени задача решалась с точностью всего лишь 68,5 %.


            image


            И вновь прорыва добилась команда из Deepmind: на датасете CLEVR они достигли super-human точности в 95,5 %.


            Архитектура сети весьма интересная:


            1. По текстовому вопросу с помощью pretrained LSTM получаем embedding (представление) вопроса.
            2. По картинке с помощью CNN (всего четыре слоя) получаем feature maps (фичи, характеризующие картинку).
            3. Далее формируем попарные комбинации покоординатных slice’ов feature maps (желтые, синие, красные на картинке ниже), добавляем к каждой координаты и текстовый embedding.
            4. Прогоняем все эти тройки через еще одну сеть, суммируем.
            5. Полученное представление прогоняем через еще одну feedforward-сеть, которая уже на софтмаксе выдает ответ.


              image



            3.3. Pix2Code


            Интересное применение нейросетям придумала компания Uizard: по скриншоту от дизайнера интерфейсов генерировать код верстки.


            image


            Крайне полезное применение нейросетей, которое может облегчить жизнь при разработке софта. Авторы утверждают, что получили 77 % точности. Понятно, что это пока исследовательская работа и о боевом применении речи не идет.


            Кода и датасета в open source пока нет, но обещают выложить.





            3.4. SketchRNN: учим машину рисовать


            Возможно, вы видели страничку Quick, Draw! от Google с призывом нарисовать скетчи различных объектов за 20 секунд. Корпорация собирала этот датасет для того, чтобы обучить нейросеть рисовать, о чем Google рассказала в своем блоге и статье.


            image


            Собранный датасет состоит из 70 тыс. скетчей, он был в итоге выложен в открытый доступ. Скетчи представляют собой не картинки, а детализированные векторные представления рисунков (в какой точке пользователь нажал «карандаш», отпустил, куда провел линию и так далее).


            Исследователи обучили Sequence-to-Sequence Variational Autoencoder (VAE) c использованием RNN в качестве механизма кодирования/декодирования.


            image


            В итоге, как и положено автоенкодеру, модель получает латентный вектор, который характеризует исходную картинку.


            image


            Поскольку декодер умеет извлекать из этого вектора рисунок, то можно его менять и получать новые скетчи.


            image


            И даже выполнять векторную арифметику, чтобы соорудить котосвина:


            image


            3.5. GAN


            Одна из самых горячих тем в Deep Learning — Generative Adversarial Networks (GAN). Чаще всего эту идею используют для работы с изображениями, поэтому объясню концепцию именно на них.


            Суть идеи состоит в соревновании двух сетей — Генератора и Дискриминатора. Первая сеть создает картинку, а вторая пытается понять, реальная это картинка или сгенерированная.


            Схематично это выглядит так:


            image


            Во время обучения генератор из случайного вектора (шума) генерирует изображение и подает на вход дискриминатору, который говорит, фальшивка это или нет. Дискриминатору также подаются реальные изображения из датасета.


            Обучать такую конструкцию часто тяжело из-за того, что трудно найти точку равновесия двух сетей, чаще всего дискриминатор побеждает и обучение стагнирует. Однако преимущество системы в том, что мы можем решать задачи, в которых нам тяжело задать loss-функцию (например, улучшение качества фотографии), мы это отдаем на откуп дискриминатору.


            Классический пример результата обучения GAN — картинки спален или лиц.


            image


            image


            Ранее мы рассматривали автокодировщики (Sketch-RNN), которые кодируют исходные данные в латентное представление. С генератором получается то же самое.


            Очень наглядно идея генерирования изображения по вектору на примере лиц показана тут (можно изменять вектор и посмотреть, какие выходят лица).


            image


            Работает все та же арифметика над латентным пространством: «мужчина в очках» минус «мужчина» плюс «женщина» равно «женщина в очках».


            image


            3.6. Изменение возраста лица с помощью GAN


            Если при обучении подсунуть в латентный вектор контролируемый параметр, то при генерировании его можно менять и так управлять нужным образом на картинке. Этот подход именуется Conditional GAN.


            Так поступили авторы статьи «Face Aging With Conditional Generative Adversarial Networks». Обучив машину на датасете IMDB с известным возрастом актеров, исследователи получили возможность менять возраст лица.


            image


            3.7. Фотографии профессионального уровня


            В Google нашли еще одно интересное применение GAN — выбор и улучшение фотографий. GAN обучали на датасете профессиональных фотографий: генератор пытается улучшить плохие фотографии (профессионально снятые и ухудшенные с помощью специальных фильтров), а дискриминатор — различить «улучшенные» фотографии и реальные профессиональные.


            Обученный алгоритм прошелся по панорамам Google Street View в поиске лучших композиций и получил некоторые снимки профессионального и полупрофессионального качества (по оценкам фотографов).


            image


            image


            3.8. Синтезирование из текстового описания в изображение


            Впечатляющий пример использования GAN — генерирование картинок по тексту.


            image


            Авторы статьи предлагают подавать embedding текста на вход не только генератору (conditional GAN), но и дискриминатору, чтобы он проверял соответствие текста картинке. Чтобы дискриминатор научился выполнять свою функцию, дополнительно в обучение добавляли пары с неверным текстом для реальных картинок.


            image


            3.9. Pix2pix


            Одна из ярких статей конца 2016 года — «Image-to-Image Translation with Conditional Adversarial Networks» Berkeley AI Research (BAIR). Исследователи решали проблему image-to-image генерирования, когда, например, требуется по снимку со спутника создать карту или по наброску предметов — их реалистичную текстуру.


            image


            Это еще один пример успешной работы conditional GAN, в данном случае condition идет на целую картинку. В качестве архитектуры генератора использовалась UNet, популярная в сегментации изображений, а для борьбы с размытыми изображениями в качестве дискриминатора взяли новый классификатор PatchGAN (картинка нарезается на N патчей, и предсказание fake/real идет по каждому из них в отдельности).


            Авторы выпустили онлайн-демо своих сетей, что вызвало огромный интерес у пользователей.


            image


            Исходный код.


            3.10. CycleGAN


            Чтобы применить Pix2Pix, требуется датасет с соответствующими парами картинок из разных доменов. В случае, например, с картами собрать такой датасет не проблема. Но если хочется сделать что-то более сложное вроде «трансфигурирования» объектов или стилизации, то пар объектов не найти в принципе. Поэтому авторы Pix2Pix решили развить свою идею и придумали CycleGAN для трансфера между разными доменами изображений без конкретных пар — Unpaired Image-to-Image Translation.


            image


            Идея состоит в следующем: мы учим две пары генератор-дискриминатор из одного домена в другой и обратно, при этом мы требуем cycle consistency — после последовательного применения генераторов должно получиться изображение, похожее на исходное по L1 loss’у. Цикличный loss требуется для того, чтобы генератор не начал просто транслировать картинки одного домена в совершенно не связанные с исходным изображением.


            image


            Такой подход позволяет выучить маппинг лошади –> зебры.



            Такие трансформации работают нестабильно и часто создают неудачные варианты:


            image


            Исходный код.


            3.11. Разработка молекул в онкологии


            Машинное обучение сейчас приходит и в медицину. Помимо распознавания УЗИ, МРТ и диагностики его можно использовать для поиска новых лекарств для борьбы с раком.


            Мы уже подробно писали об этом исследовании тут, поэтому коротко: с помощью Adversarial Auto Encoder (AAE) можно выучить латентное представление молекул и дальше с его помощью искать новые. В результате нашли 69 молекул, половина из которых применяются для борьбы с раком, остальные имеют серьезный потенциал.


            image


            3.12. Adversarial-атаки


            Сейчас активно исследуется тема с adversarial-атаками. Что это такое? Стандартные сети, обучаемые, например, на ImageNet, совершенно неустойчивы к добавлению специального шума к классифицируемой картинке. На примере ниже мы видим, что картинка с шумом для человеческого глаза практически не меняется, однако модель сходит с ума и предсказывает совершенно иной класс.


            image


            Устойчивость достигается с помощью, например, Fast Gradient Sign Method (FGSM): имея доступ к параметрам модели, можно сделать один или несколько градиентных шагов в сторону нужного класса и изменить исходную картинку.


            Одна из задач на Kaggle к грядущему NIPS как раз связана с этим: участникам предлагается создать универсальные атаки/защиты, которые в итоге запускаются все против всех для определения лучших.


            Зачем нам вообще исследовать эти атаки? Во-первых, если мы хотим защитить свои продукты, то можно добавлять к капче шум, чтобы мешать спамерам распознавать ее автоматом. Во-вторых, алгоритмы все больше и больше участвуют в нашей жизни — системы распознавания лиц, беспилотные автомобили. При этом злоумышленники могут использовать недостатки алгоритмов. Вот пример, когда специальные очки позволяют обмануть систему распознавания лиц и «представиться» другим человеком. Так что модели надо будет учить с учетом возможных атак.


            image


            Такие манипуляции со знаками тоже не позволяют правильно их распознать.


            image


            Набор статей от организаторов конкурса.


            Уже написанные библиотеки для атак: cleverhans и foolbox.


            4. Обучение с подкреплением


            Reinforcement learning (RL), или обучение с подкреплением, — также сейчас одна из интереснейших и активно развивающихся тем в машинном обучении.


            Суть подхода заключается в выучивании успешного поведения агента в среде, которая при взаимодействии дает обратную связь (reward). В общем, через опыт — так же, как учатся люди в течение жизни.


            image


            RL активно применяют в играх, роботах, управлении системами (трафиком, например).


            Разумеется, все слышали о победах AlphaGo от DeepMind в игре го над лучшими профессионалами. Статья авторов была опубликована в Nature «Mastering the game of Go». При обучении разработчики использовали RL: бот играл сам с собой для совершенствования своих стратегий.


            4.1. Обучение с подкреплением с неконтролируемыми вспомогательными задачами


            В предыдущие годы DeepMind научился с помощью DQN играть в аркадные игры лучше человека. Сейчас алгоритмы учат играть в более сложные игры типа Doom.


            Много внимания уделено ускорению обучения, потому что наработка опыта агента во взаимодействии со средой требует многих часов обучения на современных GPU.


            Deepmind в своем блоге рассказывает о том, что введение дополнительных loss’ов (auxiliary tasks, вспомогательных задач), таких как предсказание изменения кадра (pixel control), чтобы агент лучше понимал последствия действий, существенно ускоряет обучение.



            Результаты обучения:





            4.2. Обучающиеся роботы


            В OpenAI активно исследуют обучение человеком агента в виртуальной среде, что более безопасно для экспериментов, чем в реальной жизни ;)


            В одном из исследований команда показала, что one-shot learning возможно: человек показывает в VR, как выполнить определенную задачу, и алгоритму достаточно одной демонстрации, чтобы выучить ее и далее воспроизвести в реальных условиях.


            image


            Эх, если бы с людьми было так просто ;)


            4.3. Обучение на человеческих предпочтениях


            Работа OpenAI и DeepMind на ту же тему. Суть состоит в следующем: у агента есть некая задача, алгоритм предоставляет на суд человеку два возможных варианта решения, и человек указывает, какой лучше. Процесс повторяется итеративно, и алгоритм за 900 бит обратной связи (бинарной разметки) от человека выучился решать задачу.


            image



            Как всегда, человеку надо быть осторожным и думать, чему он учит машину. Например, оценщик решил, что алгоритм действительно хотел взять объект, но на самом деле тот лишь имитировал это действие.


            image


            4.4. Движение в сложных окружениях


            Еще одно исследование от DeepMind. Чтобы научить робота сложному поведению (ходить/прыгать/...), да еще и похожему на человеческое, нужно сильно заморочиться с выбором функции потерь, которая будет поощрять нужное поведение. Но хотелось бы, чтобы алгоритм сам выучивал сложное поведение, опираясь на простые reward.


            Исследователям удалось этого добиться: они научили агентов (эмуляторы тел) совершать сложные действия с помощью конструирования сложной среды с препятствиями и с простым reward за прогресс в передвижении.


            image


            Впечатляющее видео с результатами. Но оно гораздо забавнее с наложенным звуком ;)







            Напоследок дам ссылку на опубликованные недавно алгоритмы обучения RL от OpenAI. Теперь можно использовать более современные решения, чем уже ставший стандартным DQN.


            5. Прочее


            5.1. Охлаждение дата-центра


            В июле 2017-го Google рассказала, что воспользовалась разработками DeepMind в машинном обучении, чтобы сократить энергозатраты своего дата-центра.


            На основе информации с тысяч датчиков в дата-центре разработчики Google натренировали ансамбль нейросетей для предсказания PUE (Power Usage Effectiveness) и более эффективного управления дата-центром. Это впечатляющий и значимый пример практического применения ML.


            image


            5.2. Одна модель на все задачи


            Как вы знаете, обученные модели плохо переносятся от задачи к задаче, под каждую задачу приходится обучать/дообучать специфичную модель. Небольшой шаг в сторону универсальности моделей сделала Google Brain в своей статье «One Model To Learn Them All».


            Исследователи обучили модель, которая выполняет восемь задач из разных доменов (текст, речь, изображения). Например, перевод с разных языков, парсинг текста, распознавание изображений и звука.


            image


            Для достижения этой цели сделали сложную архитектуру сети с различными блоками для обработки разных входных данных и генерирования результата. Блоки для encoder/decoder делятся на три типа: сверточные, attention, gated mixture of experts (MoE).


            image


            image


            Основные итоги обучения:


            • получились почти совершенные модели (авторы не делали тонкой настройки гиперпараметров);
            • происходит передача знаний между разными доменами, то есть на задачах с большим количеством данных производительность будет почти такой же. А на маленьких задачах (например, на парсинге) — лучше;
            • блоки, нужные для разных задач, не мешают друг другу и даже иногда помогают, например, MoE — для Imagenet-задачи.

            Кстати, эта модель есть в tensor2tensor.


            5.3. Обучение на Imagenet за один час


            В своем посте сотрудники Facebook рассказали, как их инженеры смогли добиться обучения модели Resnet-50 на Imagenet всего за один час. Правда, для этого потребовался кластер из 256 GPU (Tesla P100).


            Для распределенного обучения использовали Gloo и Caffe2. Чтобы процесс шел эффективно, пришлось адаптировать стратегию обучения при огромном батче (8192 элемента): усреднение градиентов, фаза прогрева, специальные learning rate и тому подобное. Подробнее в статье.


            В итоге удалось добиться эффективности 90% при масштабировании от 8 к 256 GPU. Теперь исследователи из Facebook могут экспериментировать еще быстрее, в отличие от простых смертных без такого кластера ;)


            6. Новости


            6.1. Беспилотные автомобили


            Сфера беспилотных автомобилей интенсивно развивается, и машины активно тестируют в боевых условиях. Из относительно недавних событий можно отметить покупку Intel’ом MobilEye, скандал вокруг Uber и украденных экс-сотрудником Google технологий, первую смерть при работе автопилота и многое другое.


            Отмечу один момент: Google Waymo запускает бета-программу. Google — пионер в этой области, и предполагается, что их технология очень хороша, ведь машины наездили уже более 3 млн миль.


            Также совсем недавно беспилотным автомобилям разрешили колесить по всем штатам США.


            6.2. Здравоохранение


            Как я уже говорил, современный ML начинает внедряться в медицину. Например, Google сотрудничает с медицинским центром для помощи диагностам.


            image


            Deepmind создал даже отдельное подразделение.


            image


            В этом году в рамках Data Science Bowl был проведен конкурс по предсказанию рака легких через год на основе подробных снимков, призовой фонд — один миллион долларов.


            6.3. Инвестиции


            Сейчас много и усердно инвестируют в ML, как до этого — в BigData.


            КНР вкладывает 150 млрд долларов в AI, чтобы стать мировым лидером индустрии.


            Для сравнения, в Baidu Research работает 1300 человек, а в том же FAIR (Facebook) — 80. На последнем KDD сотрудники Alibaba рассказывали про свой parameter server KungPeng, который работает на 100 миллиардных выборках при триллионе параметров, что «становится обычной задачей» (с).


            image




            Делайте выводы, изучайте ML. Так или иначе со временем все разработчики будут использовать машинное обучение, что станет одной из компетенций, как сегодня — умение работать с базами данных.

            Original source: habrahabr.ru (comments, light).

            https://habrahabr.ru/post/338248/


            Метки:  

            Достижения в глубоком обучении за последний год

            Четверг, 21 Сентября 2017 г. 17:28 + в цитатник
            EdT сегодня в 17:28 Разработка

            Достижения в глубоком обучении за последний год


              Привет, Хабр. В своей статье я расскажу вам, что интересного произошло в мире машинного обучения за последний год (в основном в Deep Learning). А произошло очень многое, поэтому я остановился на самых, на мой взгляд, зрелищных и/или значимых достижениях. Технические аспекты улучшения архитектур сетей в статье не приводятся. Расширяем кругозор!


              1. Текст


              1.1. Google Neural Machine Translation


              Почти год назад Google анонсировала запуск новой модели для Google Translate. Компания подробно описала архитектуру сети — Recurrent Neural Network (RNN) — в своей статье.



              Основной результат: сокращение отставания от человека по точности перевода на 55—85 % (оценивали люди по 6-балльной шкале). Воспроизвести высокие результаты этой модели сложно без огромного датасета, который имеется у Google.


              image


              2.1. Переговоры. Будет сделка?


              Вы могли слышать дурацкие новости о том, что Facebook выключила своего чат-бота, который вышел из-под контроля и выдумал свой язык. Этого чат-бота компания создала для переговоров. Его цель — вести текстовые переговоры с другим агентом и достичь сделки: как разделить на двоих предметы (книги, шляпы...). У каждого агента своя цель в переговорах, другой ее не знает. Просто уйти с переговоров без сделки нельзя.


              Для обучения собрали датасет человеческих переговоров, обучили supervised рекуррентную сеть, далее уже обученного агента с помощью reinforcement learning (обучения с подкреплением) тренировали переговариваться с самим собой, поставив ограничение: похожесть языка на человеческий.


              Бот научился одной из стратегий реальных переговоров — показывать поддельный интерес к некоторым аспектам сделки, чтобы потом по ним уступить, получив выгоду по своим настоящим целям. Это первая попытка создания подобного переговорного бота, и довольно удачная.


              image


              Подробности — в статье, код выложен в открытый доступ.


              Разумеется, новость о том, что бот якобы придумал язык, раздули на пустом месте. При обучении (при переговорах с таким же агентом) отключили ограничение похожести текста на человеческий, и алгоритм модифицировал язык взаимодействия. Ничего необычного.




              За последний год рекуррентные сети активно развивали и использовали во многих задачах и приложениях. Архитектуры рекуррентных сетей сильно усложнились, однако по некоторым направлениям похожих результатов достигают и простые feedforward-сети — DSSM. Например, Google для своей почтовой фичи Smart Reply достигла такого же качества, как и с LSTM до этого. А Яндекс запустил новый поисковый движок на основе таких сетей.


              2. Речь


              2.1. WaveNet: генерирующая модель для необработанного аудио


              Сотрудники DeepMind (компания, известная своим ботом для игры в го, ныне принадлежащая Google) рассказали в своей статье про генерирование аудио.


              Если коротко, то исследователи сделали авторегрессионную полносверточную модель WaveNet на основе предыдущих подходов к генерированию изображений (PixelRNN и PixelCNN).



              Сеть обучалась end-to-end: на вход текст, на выход аудио. Результат превосходный, разница с человеком сократилась на 50 %.


              image


              Основной недостаток сети — низкая производительность, потому что из-за авторегрессии звуки генерируются последовательно, на создание одной секунды аудио уходит около 1—2 минут.


              Английский: пример


              Если убрать зависимость сети от входного текста и оставить только зависимость от предыдущей сгенерированной фонемы, то сеть будет генерировать подобные человеческому языку фонемы, но бессмысленные.


              Генерирование голоса: пример


              Эту же модель можно применить не только к речи, но и, например, к созданию музыки. Пример аудио, сгенерированного моделью, которую обучили на датасете игры на пианино (опять же без всякой зависимости от входных данных).


              Пример пианино


              Подробности — в статье.


              2.2. Чтение по губам


              Еще одна победа машинного обучения над человеком ;) На этот раз — в чтении по губам.


              Google Deepmind в сотрудничестве с Оксфордским университетом рассказывают в статье «Lip Reading Sentences in the Wild», как их модель, обученная на телевизионном датасете, смогла превзойти профессионального lips reader’а c канала BBC.


              image


              В датасете 100 тыс. предложений с аудио и видео. Модель: LSTM на аудио, CNN + LSTM на видео, эти два state-вектора подаются в итоговую LSTM, которая генерирует результат (characters).


              image


              При обучении использовались разные варианты входных данных: аудио, видео, аудио + видео, то есть модель «омниканальна».


              image


              2.3. Синтезируя Обаму: синхронизация движения губ с аудио


              image


              Университет Вашингтона проделал серьезную работу по генерированию движения губ бывшего президента США Обамы. Выбор пал на него в том числе из-за огромного количества записей его выступления в сети (17 часов HD-видео).


              Одной сетью обойтись не удалось, получалось слишком много артефактов. Поэтому авторы статьи сделали несколько костылей (или трюков, если угодно) по улучшению текстуры и таймингам.


              image


              Результат впечатляет. Скоро нельзя будет верить даже видео с президентом ;)


              3. Компьютерное зрение


              3.1. OCR: Google Maps и Street View


              В своих посте и статье команда Google Brain рассказывает, как внедрила в свои Карты новый движок OCR (Optical Character Recognition), с помощью которого распознаются указатели улиц и вывески магазинов.


              image


              image


              В процессе разработки технологии компания составила новый FSNS (French Street Name Signs), который содержит множество сложных кейсов.


              Сеть использует для распознавания каждого знака до четырех его фотографий. С помощью CNN извлекаются фичи, взвешиваются с помощью spatial attention (учитываются пиксельные координаты), а результат подается в LSTM.


              image


              Тот же самый подход авторы применяют к задаче распознавания названий магазинов на вывесках (там может быть много «шумовых» данных, и сеть сама должна «фокусироваться» в нужных местах). Алгоритм применили к 80 млрд фотографий.


              3.2. Visual Reasoning


              Существует такой тип задач, как Visual Reasoning, то есть нейросеть должна по фотографии ответить на какой-то вопрос. Например: «Есть ли на картинке резиновые вещи того же размера, что и желтый металлический цилиндр?» Вопрос и правда нетривиальный, и до недавнего времени задача решалась с точностью всего лишь 68,5 %.


              image


              И вновь прорыва добилась команда из Deepmind: на датасете CLEVR они достигли super-human точности в 95,5 %.


              Архитектура сети весьма интересная:


              1. По текстовому вопросу с помощью pretrained LSTM получаем embedding (представление) вопроса.
              2. По картинке с помощью CNN (всего четыре слоя) получаем feature maps (фичи, характеризующие картинку).
              3. Далее формируем попарные комбинации покоординатных slice’ов feature maps (желтые, синие, красные на картинке ниже), добавляем к каждой координаты и текстовый embedding.
              4. Прогоняем все эти тройки через еще одну сеть, суммируем.
              5. Полученное представление прогоняем через еще одну feedforward-сеть, которая уже на софтмаксе выдает ответ.


                image



              3.3. Pix2Code


              Интересное применение нейросетям придумала компания Uizard: по скриншоту от дизайнера интерфейсов генерировать код верстки.


              image


              Крайне полезное применение нейросетей, которое может облегчить жизнь при разработке софта. Авторы утверждают, что получили 77 % точности. Понятно, что это пока исследовательская работа и о боевом применении речи не идет.


              Кода и датасета в open source пока нет, но обещают выложить.





              3.4. SketchRNN: учим машину рисовать


              Возможно, вы видели страничку Quick, Draw! от Google с призывом нарисовать скетчи различных объектов за 20 секунд. Корпорация собирала этот датасет для того, чтобы обучить нейросеть рисовать, о чем Google рассказала в своем блоге и статье.


              image


              Собранный датасет состоит из 70 тыс. скетчей, он был в итоге выложен в открытый доступ. Скетчи представляют собой не картинки, а детализированные векторные представления рисунков (в какой точке пользователь нажал «карандаш», отпустил, куда провел линию и так далее).


              Исследователи обучили Sequence-to-Sequence Variational Autoencoder (VAE) c использованием RNN в качестве механизма кодирования/декодирования.


              image


              В итоге, как и положено автоенкодеру, модель получает латентный вектор, который характеризует исходную картинку.


              image


              Поскольку декодер умеет извлекать из этого вектора рисунок, то можно его менять и получать новые скетчи.


              image


              И даже выполнять векторную арифметику, чтобы соорудить котосвина:


              image


              3.5. GAN


              Одна из самых горячих тем в Deep Learning — Generative Adversarial Networks (GAN). Чаще всего эту идею используют для работы с изображениями, поэтому объясню концепцию именно на них.


              Суть идеи состоит в соревновании двух сетей — Генератора и Дискриминатора. Первая сеть создает картинку, а вторая пытается понять, реальная это картинка или сгенерированная.


              Схематично это выглядит так:


              image


              Во время обучения генератор из случайного вектора (шума) генерирует изображение и подает на вход дискриминатору, который говорит, фальшивка это или нет. Дискриминатору также подаются реальные изображения из датасета.


              Обучать такую конструкцию часто тяжело из-за того, что трудно найти точку равновесия двух сетей, чаще всего дискриминатор побеждает и обучение стагнирует. Однако преимущество системы в том, что мы можем решать задачи, в которых нам тяжело задать loss-функцию (например, улучшение качества фотографии), мы это отдаем на откуп дискриминатору.


              Классический пример результата обучения GAN — картинки спален или лиц.


              image


              image


              Ранее мы рассматривали автокодировщики (Sketch-RNN), которые кодируют исходные данные в латентное представление. С генератором получается то же самое.


              Очень наглядно идея генерирования изображения по вектору на примере лиц показана тут (можно изменять вектор и посмотреть, какие выходят лица).


              image


              Работает все та же арифметика над латентным пространством: «мужчина в очках» минус «мужчина» плюс «женщина» равно «женщина в очках».


              image


              3.6. Изменение возраста лица с помощью GAN


              Если при обучении подсунуть в латентный вектор контролируемый параметр, то при генерировании его можно менять и так управлять нужным образом на картинке. Этот подход именуется Conditional GAN.


              Так поступили авторы статьи «Face Aging With Conditional Generative Adversarial Networks». Обучив машину на датасете IMDB с известным возрастом актеров, исследователи получили возможность менять возраст лица.


              image


              3.7. Фотографии профессионального уровня


              В Google нашли еще одно интересное применение GAN — выбор и улучшение фотографий. GAN обучали на датасете профессиональных фотографий: генератор пытается улучшить плохие фотографии (профессионально снятые и ухудшенные с помощью специальных фильтров), а дискриминатор — различить «улучшенные» фотографии и реальные профессиональные.


              Обученный алгоритм прошелся по панорамам Google Street View в поиске лучших композиций и получил некоторые снимки профессионального и полупрофессионального качества (по оценкам фотографов).


              image


              image


              3.8. Синтезирование из текстового описания в изображение


              Впечатляющий пример использования GAN — генерирование картинок по тексту.


              image


              Авторы статьи предлагают подавать embedding текста на вход не только генератору (conditional GAN), но и дискриминатору, чтобы он проверял соответствие текста картинке. Чтобы дискриминатор научился выполнять свою функцию, дополнительно в обучение добавляли пары с неверным текстом для реальных картинок.


              image


              3.9. Pix2pix


              Одна из ярких статей конца 2016 года — «Image-to-Image Translation with Conditional Adversarial Networks» Berkeley AI Research (BAIR). Исследователи решали проблему image-to-image генерирования, когда, например, требуется по снимку со спутника создать карту или по наброску предметов — их реалистичную текстуру.


              image


              Это еще один пример успешной работы conditional GAN, в данном случае condition идет на целую картинку. В качестве архитектуры генератора использовалась UNet, популярная в сегментации изображений, а для борьбы с размытыми изображениями в качестве дискриминатора взяли новый классификатор PatchGAN (картинка нарезается на N патчей, и предсказание fake/real идет по каждому из них в отдельности).


              Авторы выпустили онлайн-демо своих сетей, что вызвало огромный интерес у пользователей.


              image


              Исходный код.


              3.10. CycleGAN


              Чтобы применить Pix2Pix, требуется датасет с соответствующими парами картинок из разных доменов. В случае, например, с картами собрать такой датасет не проблема. Но если хочется сделать что-то более сложное вроде «трансфигурирования» объектов или стилизации, то пар объектов не найти в принципе. Поэтому авторы Pix2Pix решили развить свою идею и придумали CycleGAN для трансфера между разными доменами изображений без конкретных пар — Unpaired Image-to-Image Translation.


              image


              Идея состоит в следующем: мы учим две пары генератор-дискриминатор из одного домена в другой и обратно, при этом мы требуем cycle consistency — после последовательного применения генераторов должно получиться изображение, похожее на исходное по L1 loss’у. Цикличный loss требуется для того, чтобы генератор не начал просто транслировать картинки одного домена в совершенно не связанные с исходным изображением.


              image


              Такой подход позволяет выучить маппинг лошади –> зебры.



              Такие трансформации работают нестабильно и часто создают неудачные варианты:


              image


              Исходный код.


              3.11. Разработка молекул в онкологии


              Машинное обучение сейчас приходит и в медицину. Помимо распознавания УЗИ, МРТ и диагностики его можно использовать для поиска новых лекарств для борьбы с раком.


              Мы уже подробно писали об этом исследовании тут, поэтому коротко: с помощью Adversarial Auto Encoder (AAE) можно выучить латентное представление молекул и дальше с его помощью искать новые. В результате нашли 69 молекул, половина из которых применяются для борьбы с раком, остальные имеют серьезный потенциал.


              image


              3.12. Adversarial-атаки


              Сейчас активно исследуется тема с adversarial-атаками. Что это такое? Стандартные сети, обучаемые, например, на ImageNet, совершенно неустойчивы к добавлению специального шума к классифицируемой картинке. На примере ниже мы видим, что картинка с шумом для человеческого глаза практически не меняется, однако модель сходит с ума и предсказывает совершенно иной класс.


              image


              Устойчивость достигается с помощью, например, Fast Gradient Sign Method (FGSM): имея доступ к параметрам модели, можно сделать один или несколько градиентных шагов в сторону нужного класса и изменить исходную картинку.


              Одна из задач на Kaggle к грядущему NIPS как раз связана с этим: участникам предлагается создать универсальные атаки/защиты, которые в итоге запускаются все против всех для определения лучших.


              Зачем нам вообще исследовать эти атаки? Во-первых, если мы хотим защитить свои продукты, то можно добавлять к капче шум, чтобы мешать спамерам распознавать ее автоматом. Во-вторых, алгоритмы все больше и больше участвуют в нашей жизни — системы распознавания лиц, беспилотные автомобили. При этом злоумышленники могут использовать недостатки алгоритмов. Вот пример, когда специальные очки позволяют обмануть систему распознавания лиц и «представиться» другим человеком. Так что модели надо будет учить с учетом возможных атак.


              image


              Такие манипуляции со знаками тоже не позволяют правильно их распознать.


              image


              Набор статей от организаторов конкурса.


              Уже написанные библиотеки для атак: cleverhans и foolbox.


              4. Обучение с подкреплением


              Reinforcement learning (RL), или обучение с подкреплением, — также сейчас одна из интереснейших и активно развивающихся тем в машинном обучении.


              Суть подхода заключается в выучивании успешного поведения агента в среде, которая при взаимодействии дает обратную связь (reward). В общем, через опыт — так же, как учатся люди в течение жизни.


              image


              RL активно применяют в играх, роботах, управлении системами (трафиком, например).


              Разумеется, все слышали о победах AlphaGo от DeepMind в игре го над лучшими профессионалами. Статья авторов была опубликована в Nature «Mastering the game of Go». При обучении разработчики использовали RL: бот играл сам с собой для совершенствования своих стратегий.


              4.1. Обучение с подкреплением с неконтролируемыми вспомогательными задачами


              В предыдущие годы DeepMind научился с помощью DQN играть в аркадные игры лучше человека. Сейчас алгоритмы учат играть в более сложные игры типа Doom.


              Много внимания уделено ускорению обучения, потому что наработка опыта агента во взаимодействии со средой требует многих часов обучения на современных GPU.


              Deepmind в своем блоге рассказывает о том, что введение дополнительных loss’ов (auxiliary tasks, вспомогательных задач), таких как предсказание изменения кадра (pixel control), чтобы агент лучше понимал последствия действий, существенно ускоряет обучение.



              Результаты обучения:





              4.2. Обучающиеся роботы


              В OpenAI активно исследуют обучение человеком агента в виртуальной среде, что более безопасно для экспериментов, чем в реальной жизни ;)


              В одном из исследований команда показала, что one-shot learning возможно: человек показывает в VR, как выполнить определенную задачу, и алгоритму достаточно одной демонстрации, чтобы выучить ее и далее воспроизвести в реальных условиях.


              image


              Эх, если бы с людьми было так просто ;)


              4.3. Обучение на человеческих предпочтениях


              Работа OpenAI и DeepMind на ту же тему. Суть состоит в следующем: у агента есть некая задача, алгоритм предоставляет на суд человеку два возможных варианта решения, и человек указывает, какой лучше. Процесс повторяется итеративно, и алгоритм за 900 бит обратной связи (бинарной разметки) от человека выучился решать задачу.


              image



              Как всегда, человеку надо быть осторожным и думать, чему он учит машину. Например, оценщик решил, что алгоритм действительно хотел взять объект, но на самом деле тот лишь имитировал это действие.


              image


              4.4. Движение в сложных окружениях


              Еще одно исследование от DeepMind. Чтобы научить робота сложному поведению (ходить/прыгать/...), да еще и похожему на человеческое, нужно сильно заморочиться с выбором функции потерь, которая будет поощрять нужное поведение. Но хотелось бы, чтобы алгоритм сам выучивал сложное поведение, опираясь на простые reward.


              Исследователям удалось этого добиться: они научили агентов (эмуляторы тел) совершать сложные действия с помощью конструирования сложной среды с препятствиями и с простым reward за прогресс в передвижении.


              image


              Впечатляющее видео с результатами. Но оно гораздо забавнее с наложенным звуком ;)







              Напоследок дам ссылку на опубликованные недавно алгоритмы обучения RL от OpenAI. Теперь можно использовать более современные решения, чем уже ставший стандартным DQN.


              5. Прочее


              5.1. Охлаждение дата-центра


              В июле 2017-го Google рассказала, что воспользовалась разработками DeepMind в машинном обучении, чтобы сократить энергозатраты своего дата-центра.


              На основе информации с тысяч датчиков в дата-центре разработчики Google натренировали ансамбль нейросетей для предсказания PUE (Power Usage Effectiveness) и более эффективного управления дата-центром. Это впечатляющий и значимый пример практического применения ML.


              image


              5.2. Одна модель на все задачи


              Как вы знаете, обученные модели плохо переносятся от задачи к задаче, под каждую задачу приходится обучать/дообучать специфичную модель. Небольшой шаг в сторону универсальности моделей сделала Google Brain в своей статье «One Model To Learn Them All».


              Исследователи обучили модель, которая выполняет восемь задач из разных доменов (текст, речь, изображения). Например, перевод с разных языков, парсинг текста, распознавание изображений и звука.


              image


              Для достижения этой цели сделали сложную архитектуру сети с различными блоками для обработки разных входных данных и генерирования результата. Блоки для encoder/decoder делятся на три типа: сверточные, attention, gated mixture of experts (MoE).


              image


              image


              Основные итоги обучения:


              • получились почти совершенные модели (авторы не делали тонкой настройки гиперпараметров);
              • происходит передача знаний между разными доменами, то есть на задачах с большим количеством данных производительность будет почти такой же. А на маленьких задачах (например, на парсинге) — лучше;
              • блоки, нужные для разных задач, не мешают друг другу и даже иногда помогают, например, MoE — для Imagenet-задачи.

              Кстати, эта модель есть в tensor2tensor.


              5.3. Обучение на Imagenet за один час


              В своем посте сотрудники Facebook рассказали, как их инженеры смогли добиться обучения модели Resnet-50 на Imagenet всего за один час. Правда, для этого потребовался кластер из 256 GPU (Tesla P100).


              Для распределенного обучения использовали Gloo и Caffe2. Чтобы процесс шел эффективно, пришлось адаптировать стратегию обучения при огромном батче (8192 элемента): усреднение градиентов, фаза прогрева, специальные learning rate и тому подобное. Подробнее в статье.


              В итоге удалось добиться эффективности 90% при масштабировании от 8 к 256 GPU. Теперь исследователи из Facebook могут экспериментировать еще быстрее, в отличие от простых смертных без такого кластера ;)


              6. Новости


              6.1. Беспилотные автомобили


              Сфера беспилотных автомобилей интенсивно развивается, и машины активно тестируют в боевых условиях. Из относительно недавних событий можно отметить покупку Intel’ом MobilEye, скандал вокруг Uber и украденных экс-сотрудником Google технологий, первую смерть при работе автопилота и многое другое.


              Отмечу один момент: Google Waymo запускает бета-программу. Google — пионер в этой области, и предполагается, что их технология очень хороша, ведь машины наездили уже более 3 млн миль.


              Также совсем недавно беспилотным автомобилям разрешили колесить по всем штатам США.


              6.2. Здравоохранение


              Как я уже говорил, современный ML начинает внедряться в медицину. Например, Google сотрудничает с медицинским центром для помощи диагностам.


              image


              Deepmind создал даже отдельное подразделение.


              image


              В этом году в рамках Data Science Bowl был проведен конкурс по предсказанию рака легких через год на основе подробных снимков, призовой фонд — один миллион долларов.


              6.3. Инвестиции


              Сейчас много и усердно инвестируют в ML, как до этого — в BigData.


              КНР вкладывает 150 млрд долларов в AI, чтобы стать мировым лидером индустрии.


              Для сравнения, в Baidu Research работает 1300 человек, а в том же FAIR (Facebook) — 80. На последнем KDD сотрудники Alibaba рассказывали про свой parameter server KungPeng, который работает на 100 миллиардных выборках при триллионе параметров, что «становится обычной задачей» (с).


              image




              Делайте выводы, изучайте ML. Так или иначе со временем все разработчики будут использовать машинное обучение, что станет одной из компетенций, как сегодня — умение работать с базами данных.

              Original source: habrahabr.ru (comments, light).

              https://habrahabr.ru/post/338248/


              Метки:  

              Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

              Четверг, 21 Сентября 2017 г. 17:19 + в цитатник
              eapotapov сегодня в 17:19 Администрирование

              Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                Через три недели, в пятницу, 13-го, в коворкинге Deworkacy в Москве пройдет уже вторая конференция сообщества Uptime, тема которой — аварии в ИТ-инфраструктуре. Мест всего 300, участие бесплатное — под катом есть ссылка на регистрацию.

                image

                Немного истории


                Идея назвать так конференцию (и сообщество) пришла нам в одно и то же время с ребятами из Code&Supply в Питтсбурге. Их домен uptime.events зарегистрирован 28 марта 2017, наш uptime.community — 14 марта. Первая наша конференция состоялась в апреле, смотрите видеозаписи.

                В августе в Питтсбурге прошла подобная нашей конференция, я был на ней волонтером-звукооператором и даже немного выступал.

                image

                Что будет на Uptime day 2


                Итак, 13 октября в Москве мы обсудим ИТ-катастрофы, которые случались в жизни сотрудников Badoo, Carprice, «Ревизиума», ITSumma, «Битрикс24».

                Мой доклад — «Менеджмент инцидентов и исследование жизненного цикла аварии». Обратной стороной технического прогресса в 20 веке стало большое количество техногенных катастроф. Эксплуатация высоконагруженных проектов — это такой же технологический процесс, какие ежедневно происходят в авиации, в медицине и крупной промышленности. В этих сферах многие десятилетия есть практика расследования крупных инцидентов и детального разбора причин произошедших аварий для того, чтобы избежать их в будущем. Однако в нашей сфере по сей день отсутствуют единые практики, которые позволят не допустить повторения уже пройденных ошибок. Каждая компания подходит к этому вопросу на свой лад, зачастую не зная, что наступает на те же грабли, о которые сотни раз спотыкались их коллеги.

                Круглосуточно поддерживая сайты 350 клиентов, мы сталкиваемся в среднем с десятью серьезными авариями в день, при этом около половины из них происходит из-за человеческого фактора. Для нас важно обучить специалистов с обеих сторон тому, как можно избежать подобных аварий.

                На примере реальных аварий я покажу те методики и технологии, которые применяет ITSumma для решения уже возникших инцидентов и, что важнее, предотвращения их в будущем.

                Рассмотрим такие процессы:
                1. Фиксация того, как взаимодействуют между собой участники команды во время устранения аварии.
                2. Создание и анализ пост-мортемов аварий.
                3. Разработка рекомендаций и регламентов для нас и для клиентов.
                4. Разработка программного обеспечения для менеджмента инцидентов.
                5. Внедрение результатов анализа в ежедневные процедуры разработки и поддержки.

                Пятница, 13-е — отличный день, чтобы поговорить о катастрофах. Участие бесплатное, регистрируйтесь.
                Original source: habrahabr.ru (comments, light).

                https://habrahabr.ru/post/338432/


                Метки:  

                Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                Четверг, 21 Сентября 2017 г. 17:19 + в цитатник
                eapotapov сегодня в 17:19 Администрирование

                Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                  Через три недели, в пятницу, 13-го, в коворкинге Deworkacy в Москве пройдет уже вторая конференция сообщества Uptime, тема которой — аварии в ИТ-инфраструктуре. Мест всего 300, участие бесплатное — под катом есть ссылка на регистрацию.

                  image

                  Немного истории


                  Идея назвать так конференцию (и сообщество) пришла нам в одно и то же время с ребятами из Code&Supply в Питтсбурге. Их домен uptime.events зарегистрирован 28 марта 2017, наш uptime.community — 14 марта. Первая наша конференция состоялась в апреле, смотрите видеозаписи.

                  В августе в Питтсбурге прошла подобная нашей конференция, я был на ней волонтером-звукооператором и даже немного выступал.

                  image

                  Что будет на Uptime day 2


                  Итак, 13 октября в Москве мы обсудим ИТ-катастрофы, которые случались в жизни сотрудников Badoo, Carprice, «Ревизиума», ITSumma, «Битрикс24».

                  Мой доклад — «Менеджмент инцидентов и исследование жизненного цикла аварии». Обратной стороной технического прогресса в 20 веке стало большое количество техногенных катастроф. Эксплуатация высоконагруженных проектов — это такой же технологический процесс, какие ежедневно происходят в авиации, в медицине и крупной промышленности. В этих сферах многие десятилетия есть практика расследования крупных инцидентов и детального разбора причин произошедших аварий для того, чтобы избежать их в будущем. Однако в нашей сфере по сей день отсутствуют единые практики, которые позволят не допустить повторения уже пройденных ошибок. Каждая компания подходит к этому вопросу на свой лад, зачастую не зная, что наступает на те же грабли, о которые сотни раз спотыкались их коллеги.

                  Круглосуточно поддерживая сайты 350 клиентов, мы сталкиваемся в среднем с десятью серьезными авариями в день, при этом около половины из них происходит из-за человеческого фактора. Для нас важно обучить специалистов с обеих сторон тому, как можно избежать подобных аварий.

                  На примере реальных аварий я покажу те методики и технологии, которые применяет ITSumma для решения уже возникших инцидентов и, что важнее, предотвращения их в будущем.

                  Рассмотрим такие процессы:
                  1. Фиксация того, как взаимодействуют между собой участники команды во время устранения аварии.
                  2. Создание и анализ пост-мортемов аварий.
                  3. Разработка рекомендаций и регламентов для нас и для клиентов.
                  4. Разработка программного обеспечения для менеджмента инцидентов.
                  5. Внедрение результатов анализа в ежедневные процедуры разработки и поддержки.

                  Пятница, 13-е — отличный день, чтобы поговорить о катастрофах. Участие бесплатное, регистрируйтесь.
                  Original source: habrahabr.ru (comments, light).

                  https://habrahabr.ru/post/338432/


                  Метки:  

                  Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                  Четверг, 21 Сентября 2017 г. 17:19 + в цитатник
                  eapotapov сегодня в 17:19 Администрирование

                  Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                    Через три недели, в пятницу, 13-го, в коворкинге Deworkacy в Москве пройдет уже вторая конференция сообщества Uptime, тема которой — аварии в ИТ-инфраструктуре. Мест всего 300, участие бесплатное — под катом есть ссылка на регистрацию.

                    image

                    Немного истории


                    Идея назвать так конференцию (и сообщество) пришла нам в одно и то же время с ребятами из Code&Supply в Питтсбурге. Их домен uptime.events зарегистрирован 28 марта 2017, наш uptime.community — 14 марта. Первая наша конференция состоялась в апреле, смотрите видеозаписи.

                    В августе в Питтсбурге прошла подобная нашей конференция, я был на ней волонтером-звукооператором и даже немного выступал.

                    image

                    Что будет на Uptime day 2


                    Итак, 13 октября в Москве мы обсудим ИТ-катастрофы, которые случались в жизни сотрудников Badoo, Carprice, «Ревизиума», ITSumma, «Битрикс24».

                    Мой доклад — «Менеджмент инцидентов и исследование жизненного цикла аварии». Обратной стороной технического прогресса в 20 веке стало большое количество техногенных катастроф. Эксплуатация высоконагруженных проектов — это такой же технологический процесс, какие ежедневно происходят в авиации, в медицине и крупной промышленности. В этих сферах многие десятилетия есть практика расследования крупных инцидентов и детального разбора причин произошедших аварий для того, чтобы избежать их в будущем. Однако в нашей сфере по сей день отсутствуют единые практики, которые позволят не допустить повторения уже пройденных ошибок. Каждая компания подходит к этому вопросу на свой лад, зачастую не зная, что наступает на те же грабли, о которые сотни раз спотыкались их коллеги.

                    Круглосуточно поддерживая сайты 350 клиентов, мы сталкиваемся в среднем с десятью серьезными авариями в день, при этом около половины из них происходит из-за человеческого фактора. Для нас важно обучить специалистов с обеих сторон тому, как можно избежать подобных аварий.

                    На примере реальных аварий я покажу те методики и технологии, которые применяет ITSumma для решения уже возникших инцидентов и, что важнее, предотвращения их в будущем.

                    Рассмотрим такие процессы:
                    1. Фиксация того, как взаимодействуют между собой участники команды во время устранения аварии.
                    2. Создание и анализ пост-мортемов аварий.
                    3. Разработка рекомендаций и регламентов для нас и для клиентов.
                    4. Разработка программного обеспечения для менеджмента инцидентов.
                    5. Внедрение результатов анализа в ежедневные процедуры разработки и поддержки.

                    Пятница, 13-е — отличный день, чтобы поговорить о катастрофах. Участие бесплатное, регистрируйтесь.
                    Original source: habrahabr.ru (comments, light).

                    https://habrahabr.ru/post/338432/


                    Метки:  

                    Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                    Четверг, 21 Сентября 2017 г. 17:19 + в цитатник
                    eapotapov сегодня в 17:19 Администрирование

                    Uptime day 2: российские ИТ-компании расскажут о том, как справляются с катастрофами

                      Через три недели, в пятницу, 13-го, в коворкинге Deworkacy в Москве пройдет уже вторая конференция сообщества Uptime, тема которой — аварии в ИТ-инфраструктуре. Мест всего 300, участие бесплатное — под катом есть ссылка на регистрацию.

                      image

                      Немного истории


                      Идея назвать так конференцию (и сообщество) пришла нам в одно и то же время с ребятами из Code&Supply в Питтсбурге. Их домен uptime.events зарегистрирован 28 марта 2017, наш uptime.community — 14 марта. Первая наша конференция состоялась в апреле, смотрите видеозаписи.

                      В августе в Питтсбурге прошла подобная нашей конференция, я был на ней волонтером-звукооператором и даже немного выступал.

                      image

                      Что будет на Uptime day 2


                      Итак, 13 октября в Москве мы обсудим ИТ-катастрофы, которые случались в жизни сотрудников Badoo, Carprice, «Ревизиума», ITSumma, «Битрикс24».

                      Мой доклад — «Менеджмент инцидентов и исследование жизненного цикла аварии». Обратной стороной технического прогресса в 20 веке стало большое количество техногенных катастроф. Эксплуатация высоконагруженных проектов — это такой же технологический процесс, какие ежедневно происходят в авиации, в медицине и крупной промышленности. В этих сферах многие десятилетия есть практика расследования крупных инцидентов и детального разбора причин произошедших аварий для того, чтобы избежать их в будущем. Однако в нашей сфере по сей день отсутствуют единые практики, которые позволят не допустить повторения уже пройденных ошибок. Каждая компания подходит к этому вопросу на свой лад, зачастую не зная, что наступает на те же грабли, о которые сотни раз спотыкались их коллеги.

                      Круглосуточно поддерживая сайты 350 клиентов, мы сталкиваемся в среднем с десятью серьезными авариями в день, при этом около половины из них происходит из-за человеческого фактора. Для нас важно обучить специалистов с обеих сторон тому, как можно избежать подобных аварий.

                      На примере реальных аварий я покажу те методики и технологии, которые применяет ITSumma для решения уже возникших инцидентов и, что важнее, предотвращения их в будущем.

                      Рассмотрим такие процессы:
                      1. Фиксация того, как взаимодействуют между собой участники команды во время устранения аварии.
                      2. Создание и анализ пост-мортемов аварий.
                      3. Разработка рекомендаций и регламентов для нас и для клиентов.
                      4. Разработка программного обеспечения для менеджмента инцидентов.
                      5. Внедрение результатов анализа в ежедневные процедуры разработки и поддержки.

                      Пятница, 13-е — отличный день, чтобы поговорить о катастрофах. Участие бесплатное, регистрируйтесь.
                      Original source: habrahabr.ru (comments, light).

                      https://habrahabr.ru/post/338432/


                      Метки:  

                      Jenkins Pipeline Shared Libraries

                      Четверг, 21 Сентября 2017 г. 16:03 + в цитатник
                      Andrey_V_Markelov сегодня в 16:03 Администрирование

                      Jenkins Pipeline Shared Libraries

                        Всем привет. В данной статье хочу поделиться знаниями, полученными в процессе автоматизации развертывания наших сервисов на различные серверы в разных дата-центрах.

                        Задача была следующей: есть определенный набор скриптов для развертывания сервисов, которые нужно запускать на каждом сервере каждого дата-центра. Скрипты выполняют серию операций: проверка статуса, вывод из-под load balancer’а, выпуск версии, развертывание, проверка статуса, отправка уведомлений через email и Slack и т.д. Это просто и удобно, но с ростом числа дата-центров и сервисов процесс выкатки новой версии может занять целый день. Кроме того, за некоторые действия отвечают отдельные команды, например, настройка load balancer’а. Также хотелось, чтобы управляющий процессом код хранился в общедоступном репозитории, дабы каждый член команды мог его поддерживать.
                        Решить задачу удалось с помощью Jenkins Pipeline Shared Libraries: этапы процесса разделились визуально на логические части, код хранится в репозитории, а осуществить доставку на 20 серверов стало возможно в один клик. Ниже приведен пример подобного тестового проекта:

                        image

                        Сейчас я расскажу и покажу примеры как этого достичь. Надеюсь эта статья поможет сохранить время другим разработчикам, а также буду рад дельным комментариям.

                        Создание библиотеки


                        Первое что необходимо сделать, создать собственную библиотеку, в которой будут храниться наши функции.
                        Создаем новый репозиторий, который должен иметь следующую структуру:

                        image
                        Директория src используется для Java/Groovy классов, которые добавляются в classpath при выполнении Pipeline.
                        Директория vars используется в скриптах, которые определяют глобальные переменные, доступные из Pipeline.

                        Ниже приведен пример Groovy класса
                        @Grab(group = 'org.apache.commons', module = 'commons-lang3', version = '3.6')
                        import org.apache.commons.lang3.StringUtils
                        
                        class Deployer {
                            int tries = 0
                            Script script
                        
                            def run() {
                                while (tries < 10) {
                                    Thread.sleep(1000)
                                    tries++
                                    script.echo("tries is numeric: " + StringUtils.isAlphanumeric("" + tries))
                                }
                            }
                        }
                        

                        В классах можно использовать любые возможности языка: создавать потоки, соединяться по FTP и т.д.
                        Важно:
                        — чтобы выводить в лог консоли из Pipeline, нужно передавать Script;
                        — для импорта библиотек просто используем @Grab.

                        Ниже пример скрипта:
                        #!/usr/bin/env groovy
                        
                        def call(body) {
                            echo "Start Deploy"
                        
                            new Deployer(script:this).run()
                        
                            echo "Deployed"
                            currentBuild.result = 'SUCCESS' //FAILURE to fail
                        
                            return this
                        }
                        

                        В скриптах можно использовать любые возможности языка и также получить переменные сборки и параметры Jenkins.
                        Важно:
                        — Чтобы остановить выполнение достаточно установить значение currentBuild.result = 'FAILURE';
                        — Получить параметры параметризованной сборки можно через переменную env. Например, env.param1.

                        Вот пример репозитория с другими примерами.

                        Подключение репозитория


                        Следующий шаг — добавить наш репозиторий как глобальную библиотеку Pipeline.
                        Для этого в Jenkins нужно перейти: Manage Jenkins -> Configure System (Настроить Jenkins -> Конфигурирование системы). В блоке Global Pipeline Libraries, добавить наш репозиторий, как на картинке ниже:

                        image

                        Создание Pipeline


                        Последний шаг — создать Pipeline.
                        Наш Pipeline будет выглядеть следующим образом:
                        @Library('jenkins-pipeline-shared-lib-sample')_
                        
                        stage('Print Build Info') {
                            printBuildinfo {
                                name = "Sample Name"
                            }
                        } stage('Disable balancer') {
                            disableBalancerUtils()
                        } stage('Deploy') {
                            deploy()
                        } stage('Enable balancer') {
                            enableBalancerUtils()
                        } stage('Check Status') {
                            checkStatus()
                        }
                        

                        Т.е. мы просто добавляем @Library('jenkins-pipeline-shared-lib-sample')_ (не забываем добавить _ в конце) и вызываем наши функции по имени скриптов, например deploy.

                        Наш Pipeline готов.

                        В следующий раз я покажу, как я настраивал параметризованную сборку, чтобы элегантно получить зависимые параметры из REST сервиса.

                        Спасибо за внимание!
                        Original source: habrahabr.ru (comments, light).

                        https://habrahabr.ru/post/338032/


                        Метки:  

                        Jenkins Pipeline Shared Libraries

                        Четверг, 21 Сентября 2017 г. 16:03 + в цитатник
                        Andrey_V_Markelov сегодня в 16:03 Администрирование

                        Jenkins Pipeline Shared Libraries

                          Всем привет. В данной статье хочу поделиться знаниями, полученными в процессе автоматизации развертывания наших сервисов на различные серверы в разных дата-центрах.

                          Задача была следующей: есть определенный набор скриптов для развертывания сервисов, которые нужно запускать на каждом сервере каждого дата-центра. Скрипты выполняют серию операций: проверка статуса, вывод из-под load balancer’а, выпуск версии, развертывание, проверка статуса, отправка уведомлений через email и Slack и т.д. Это просто и удобно, но с ростом числа дата-центров и сервисов процесс выкатки новой версии может занять целый день. Кроме того, за некоторые действия отвечают отдельные команды, например, настройка load balancer’а. Также хотелось, чтобы управляющий процессом код хранился в общедоступном репозитории, дабы каждый член команды мог его поддерживать.
                          Решить задачу удалось с помощью Jenkins Pipeline Shared Libraries: этапы процесса разделились визуально на логические части, код хранится в репозитории, а осуществить доставку на 20 серверов стало возможно в один клик. Ниже приведен пример подобного тестового проекта:

                          image

                          Сейчас я расскажу и покажу примеры как этого достичь. Надеюсь эта статья поможет сохранить время другим разработчикам, а также буду рад дельным комментариям.

                          Создание библиотеки


                          Первое что необходимо сделать, создать собственную библиотеку, в которой будут храниться наши функции.
                          Создаем новый репозиторий, который должен иметь следующую структуру:

                          image
                          Директория src используется для Java/Groovy классов, которые добавляются в classpath при выполнении Pipeline.
                          Директория vars используется в скриптах, которые определяют глобальные переменные, доступные из Pipeline.

                          Ниже приведен пример Groovy класса
                          @Grab(group = 'org.apache.commons', module = 'commons-lang3', version = '3.6')
                          import org.apache.commons.lang3.StringUtils
                          
                          class Deployer {
                              int tries = 0
                              Script script
                          
                              def run() {
                                  while (tries < 10) {
                                      Thread.sleep(1000)
                                      tries++
                                      script.echo("tries is numeric: " + StringUtils.isAlphanumeric("" + tries))
                                  }
                              }
                          }
                          

                          В классах можно использовать любые возможности языка: создавать потоки, соединяться по FTP и т.д.
                          Важно:
                          — чтобы выводить в лог консоли из Pipeline, нужно передавать Script;
                          — для импорта библиотек просто используем @Grab.

                          Ниже пример скрипта:
                          #!/usr/bin/env groovy
                          
                          def call(body) {
                              echo "Start Deploy"
                          
                              new Deployer(script:this).run()
                          
                              echo "Deployed"
                              currentBuild.result = 'SUCCESS' //FAILURE to fail
                          
                              return this
                          }
                          

                          В скриптах можно использовать любые возможности языка и также получить переменные сборки и параметры Jenkins.
                          Важно:
                          — Чтобы остановить выполнение достаточно установить значение currentBuild.result = 'FAILURE';
                          — Получить параметры параметризованной сборки можно через переменную env. Например, env.param1.

                          Вот пример репозитория с другими примерами.

                          Подключение репозитория


                          Следующий шаг — добавить наш репозиторий как глобальную библиотеку Pipeline.
                          Для этого в Jenkins нужно перейти: Manage Jenkins -> Configure System (Настроить Jenkins -> Конфигурирование системы). В блоке Global Pipeline Libraries, добавить наш репозиторий, как на картинке ниже:

                          image

                          Создание Pipeline


                          Последний шаг — создать Pipeline.
                          Наш Pipeline будет выглядеть следующим образом:
                          @Library('jenkins-pipeline-shared-lib-sample')_
                          
                          stage('Print Build Info') {
                              printBuildinfo {
                                  name = "Sample Name"
                              }
                          } stage('Disable balancer') {
                              disableBalancerUtils()
                          } stage('Deploy') {
                              deploy()
                          } stage('Enable balancer') {
                              enableBalancerUtils()
                          } stage('Check Status') {
                              checkStatus()
                          }
                          

                          Т.е. мы просто добавляем @Library('jenkins-pipeline-shared-lib-sample')_ (не забываем добавить _ в конце) и вызываем наши функции по имени скриптов, например deploy.

                          Наш Pipeline готов.

                          В следующий раз я покажу, как я настраивал параметризованную сборку, чтобы элегантно получить зависимые параметры из REST сервиса.

                          Спасибо за внимание!
                          Original source: habrahabr.ru (comments, light).

                          https://habrahabr.ru/post/338032/


                          Метки:  

                          Jenkins Pipeline Shared Libraries

                          Четверг, 21 Сентября 2017 г. 16:03 + в цитатник
                          Andrey_V_Markelov сегодня в 16:03 Администрирование

                          Jenkins Pipeline Shared Libraries

                            Всем привет. В данной статье хочу поделиться знаниями, полученными в процессе автоматизации развертывания наших сервисов на различные серверы в разных дата-центрах.

                            Задача была следующей: есть определенный набор скриптов для развертывания сервисов, которые нужно запускать на каждом сервере каждого дата-центра. Скрипты выполняют серию операций: проверка статуса, вывод из-под load balancer’а, выпуск версии, развертывание, проверка статуса, отправка уведомлений через email и Slack и т.д. Это просто и удобно, но с ростом числа дата-центров и сервисов процесс выкатки новой версии может занять целый день. Кроме того, за некоторые действия отвечают отдельные команды, например, настройка load balancer’а. Также хотелось, чтобы управляющий процессом код хранился в общедоступном репозитории, дабы каждый член команды мог его поддерживать.
                            Решить задачу удалось с помощью Jenkins Pipeline Shared Libraries: этапы процесса разделились визуально на логические части, код хранится в репозитории, а осуществить доставку на 20 серверов стало возможно в один клик. Ниже приведен пример подобного тестового проекта:

                            image

                            Сейчас я расскажу и покажу примеры как этого достичь. Надеюсь эта статья поможет сохранить время другим разработчикам, а также буду рад дельным комментариям.

                            Создание библиотеки


                            Первое что необходимо сделать, создать собственную библиотеку, в которой будут храниться наши функции.
                            Создаем новый репозиторий, который должен иметь следующую структуру:

                            image
                            Директория src используется для Java/Groovy классов, которые добавляются в classpath при выполнении Pipeline.
                            Директория vars используется в скриптах, которые определяют глобальные переменные, доступные из Pipeline.

                            Ниже приведен пример Groovy класса
                            @Grab(group = 'org.apache.commons', module = 'commons-lang3', version = '3.6')
                            import org.apache.commons.lang3.StringUtils
                            
                            class Deployer {
                                int tries = 0
                                Script script
                            
                                def run() {
                                    while (tries < 10) {
                                        Thread.sleep(1000)
                                        tries++
                                        script.echo("tries is numeric: " + StringUtils.isAlphanumeric("" + tries))
                                    }
                                }
                            }
                            

                            В классах можно использовать любые возможности языка: создавать потоки, соединяться по FTP и т.д.
                            Важно:
                            — чтобы выводить в лог консоли из Pipeline, нужно передавать Script;
                            — для импорта библиотек просто используем @Grab.

                            Ниже пример скрипта:
                            #!/usr/bin/env groovy
                            
                            def call(body) {
                                echo "Start Deploy"
                            
                                new Deployer(script:this).run()
                            
                                echo "Deployed"
                                currentBuild.result = 'SUCCESS' //FAILURE to fail
                            
                                return this
                            }
                            

                            В скриптах можно использовать любые возможности языка и также получить переменные сборки и параметры Jenkins.
                            Важно:
                            — Чтобы остановить выполнение достаточно установить значение currentBuild.result = 'FAILURE';
                            — Получить параметры параметризованной сборки можно через переменную env. Например, env.param1.

                            Вот пример репозитория с другими примерами.

                            Подключение репозитория


                            Следующий шаг — добавить наш репозиторий как глобальную библиотеку Pipeline.
                            Для этого в Jenkins нужно перейти: Manage Jenkins -> Configure System (Настроить Jenkins -> Конфигурирование системы). В блоке Global Pipeline Libraries, добавить наш репозиторий, как на картинке ниже:

                            image

                            Создание Pipeline


                            Последний шаг — создать Pipeline.
                            Наш Pipeline будет выглядеть следующим образом:
                            @Library('jenkins-pipeline-shared-lib-sample')_
                            
                            stage('Print Build Info') {
                                printBuildinfo {
                                    name = "Sample Name"
                                }
                            } stage('Disable balancer') {
                                disableBalancerUtils()
                            } stage('Deploy') {
                                deploy()
                            } stage('Enable balancer') {
                                enableBalancerUtils()
                            } stage('Check Status') {
                                checkStatus()
                            }
                            

                            Т.е. мы просто добавляем @Library('jenkins-pipeline-shared-lib-sample')_ (не забываем добавить _ в конце) и вызываем наши функции по имени скриптов, например deploy.

                            Наш Pipeline готов.

                            В следующий раз я покажу, как я настраивал параметризованную сборку, чтобы элегантно получить зависимые параметры из REST сервиса.

                            Спасибо за внимание!
                            Original source: habrahabr.ru (comments, light).

                            https://habrahabr.ru/post/338032/


                            Метки:  

                            Jenkins Pipeline Shared Libraries

                            Четверг, 21 Сентября 2017 г. 16:03 + в цитатник
                            Andrey_V_Markelov сегодня в 16:03 Администрирование

                            Jenkins Pipeline Shared Libraries

                              Всем привет. В данной статье хочу поделиться знаниями, полученными в процессе автоматизации развертывания наших сервисов на различные серверы в разных дата-центрах.

                              Задача была следующей: есть определенный набор скриптов для развертывания сервисов, которые нужно запускать на каждом сервере каждого дата-центра. Скрипты выполняют серию операций: проверка статуса, вывод из-под load balancer’а, выпуск версии, развертывание, проверка статуса, отправка уведомлений через email и Slack и т.д. Это просто и удобно, но с ростом числа дата-центров и сервисов процесс выкатки новой версии может занять целый день. Кроме того, за некоторые действия отвечают отдельные команды, например, настройка load balancer’а. Также хотелось, чтобы управляющий процессом код хранился в общедоступном репозитории, дабы каждый член команды мог его поддерживать.
                              Решить задачу удалось с помощью Jenkins Pipeline Shared Libraries: этапы процесса разделились визуально на логические части, код хранится в репозитории, а осуществить доставку на 20 серверов стало возможно в один клик. Ниже приведен пример подобного тестового проекта:

                              image

                              Сейчас я расскажу и покажу примеры как этого достичь. Надеюсь эта статья поможет сохранить время другим разработчикам, а также буду рад дельным комментариям.

                              Создание библиотеки


                              Первое что необходимо сделать, создать собственную библиотеку, в которой будут храниться наши функции.
                              Создаем новый репозиторий, который должен иметь следующую структуру:

                              image
                              Директория src используется для Java/Groovy классов, которые добавляются в classpath при выполнении Pipeline.
                              Директория vars используется в скриптах, которые определяют глобальные переменные, доступные из Pipeline.

                              Ниже приведен пример Groovy класса
                              @Grab(group = 'org.apache.commons', module = 'commons-lang3', version = '3.6')
                              import org.apache.commons.lang3.StringUtils
                              
                              class Deployer {
                                  int tries = 0
                                  Script script
                              
                                  def run() {
                                      while (tries < 10) {
                                          Thread.sleep(1000)
                                          tries++
                                          script.echo("tries is numeric: " + StringUtils.isAlphanumeric("" + tries))
                                      }
                                  }
                              }
                              

                              В классах можно использовать любые возможности языка: создавать потоки, соединяться по FTP и т.д.
                              Важно:
                              — чтобы выводить в лог консоли из Pipeline, нужно передавать Script;
                              — для импорта библиотек просто используем @Grab.

                              Ниже пример скрипта:
                              #!/usr/bin/env groovy
                              
                              def call(body) {
                                  echo "Start Deploy"
                              
                                  new Deployer(script:this).run()
                              
                                  echo "Deployed"
                                  currentBuild.result = 'SUCCESS' //FAILURE to fail
                              
                                  return this
                              }
                              

                              В скриптах можно использовать любые возможности языка и также получить переменные сборки и параметры Jenkins.
                              Важно:
                              — Чтобы остановить выполнение достаточно установить значение currentBuild.result = 'FAILURE';
                              — Получить параметры параметризованной сборки можно через переменную env. Например, env.param1.

                              Вот пример репозитория с другими примерами.

                              Подключение репозитория


                              Следующий шаг — добавить наш репозиторий как глобальную библиотеку Pipeline.
                              Для этого в Jenkins нужно перейти: Manage Jenkins -> Configure System (Настроить Jenkins -> Конфигурирование системы). В блоке Global Pipeline Libraries, добавить наш репозиторий, как на картинке ниже:

                              image

                              Создание Pipeline


                              Последний шаг — создать Pipeline.
                              Наш Pipeline будет выглядеть следующим образом:
                              @Library('jenkins-pipeline-shared-lib-sample')_
                              
                              stage('Print Build Info') {
                                  printBuildinfo {
                                      name = "Sample Name"
                                  }
                              } stage('Disable balancer') {
                                  disableBalancerUtils()
                              } stage('Deploy') {
                                  deploy()
                              } stage('Enable balancer') {
                                  enableBalancerUtils()
                              } stage('Check Status') {
                                  checkStatus()
                              }
                              

                              Т.е. мы просто добавляем @Library('jenkins-pipeline-shared-lib-sample')_ (не забываем добавить _ в конце) и вызываем наши функции по имени скриптов, например deploy.

                              Наш Pipeline готов.

                              В следующий раз я покажу, как я настраивал параметризованную сборку, чтобы элегантно получить зависимые параметры из REST сервиса.

                              Спасибо за внимание!
                              Original source: habrahabr.ru (comments, light).

                              https://habrahabr.ru/post/338032/


                              Метки:  

                              Поиск сообщений в rss_rss_hh_full
                              Страницы: 1824 ... 1542 1541 [1540] 1539 1538 ..
                              .. 1 Календарь