(я новичок в ML, поэтому, пожалуйста, извините меня, если я говорю / делаю фигню ...)
Что я пытался сделать:
Я пыталсясоздать приложение для изучения ML (чтобы попасть в SwiftUI и CoreML). Приложение предназначено для того, чтобы научить какую-то нейронную сеть играть в крестики-нолики, используя обучение с подкреплением. Для этого вы можете сыграть AIPlayer
против RandomPlayer
, AlgorithmicPlayer
, самого себя или себя. AIPlayer
должен изучать каждую игру, в которую играл, путем обновления базовой модели, используя результаты игры и выборки, сделанные во время игры.
Проблема
Проблема в том, чтоинициализация MLUpdateTask
завершается неудачно после определенного количества обновлений с сигналом SIGABRT. Таким образом, приложение вылетает. Точная сумма зависит от устройства. При запуске его на моем iPhone 6s 240-я инициализация MLUpdateTask
завершается неудачно, на симуляторе это 243-я.
Я получаю сообщение об ошибке:
libc++abi.dylib: terminating with uncaught exception of type std::runtime_error: Error loading file: /private/var/containers/Bundle/Application/714E7417-B792-4F80-8EAE-A2855E138A95/TicTacToe.app/UpdatableNNClassifier.mlmodelc/model.espresso.weights
Я проследилошибка до этой строки ... весь код на GitHub. https://github.com/theMomax/TicTacToe/blob/0182db0af27498d504fb5dcfd0556267e23c063b/TicTacToe/MLBase.swift#L132
Что я пытался решить эту проблему:
Я пытался уменьшить количество слоев в моей модели. Без эффекта.
Я пытался иметь только одну задачу обновления за раз. Никакого эффекта.
Я перенес все приложение на macOS. Это «решило» проблему.
Модель
Этот ноутбук является основой для , который я использовал для производства CoreML Model . Я только изменил то, что было необходимо для адаптации модели к моим форматам ввода / вывода. Возможно, модель, которая у меня есть сейчас, не сможет на самом деле учиться / совершенствоваться из-за ее структуры, но я не думаю, что это актуально сейчас.
Система
Mac:10,15 бета (19A582a)
iPhone: 13.1.2 (17A860)
Xcode: 11,1 (11A1027)
Обновление кода
Здесь - это файл на GitHub. Моя ссылка здесь это видео от WWDC. Я попытался удалить ненужные части ниже и добавить некоторые комментарии, описывающие, когда каждая функция вызывается ...
// is initialized once on startup
class MLWrapper {
let bundle = Bundle(for: UpdatableNNClassifier.self)
let updatableModelURL: URL
var model = UpdatableNNClassifier()
var trainingData: [(gameboard: [Position: FieldState], pick: Position)] = []
init() {
self.updatableModelURL = bundle.url(forResource: "UpdatableNNClassifier", withExtension: "mlmodelc")!
}
// Returns a randomly selected alternative to pick.
private func other(than pick: Position, in gameboard: [Position: FieldState?]) -> Position? {
// ...
}
private func convertInput(gameboard: [Position: FieldState]) -> MLMultiArray {
// ...
}
private func convertOutput(output: UpdatableNNClassifierOutput) -> Position? {
// ...
}
// is called each time the `AIPlayer` is supposed to make a pick
func predict(on gameboard: [Position: FieldState]) -> Position? {
let input = convertInput(gameboard: gameboard)
if let output = try? model.prediction(gameboard: input) {
if let result = convertOutput(output: output) {
// record input and output, so that it can be used to train
// train the model, when the game's outcome is known
trainingData.append((gameboard, result))
return result
} else {
return nil
}
} else {
print("Unexpected runtime error in \(model).")
return nil
}
}
// is called after a game is completed
func reflect(on outcome: Outcome) {
do {
let bp: MLBatchProvider = try MLArrayBatchProvider(dictionary: ["gameboard": trainingData.compactMap { i in
return convertInput(gameboard: i.gameboard)
}, "pick": trainingData.compactMap({ I in
// in case the `AIPlayer` won or achieved a draw, its pick was good, otherwise, try any other pick next time
outcome != .defeat ? i.pick.description() : other(than: i.pick, in: i.gameboard)?.description() ?? i.pick.description()
})])
// reset trainingData
trainingData = []
// the line below is the one that fails
let updateTask = try MLUpdateTask(forModelAt: updatableModelURL, trainingData: bp, configuration: self.model.model.configuration, completionHandler: { ctx in
if ctx.task.error == nil {
self.model.model = ctx.model
} else {
print(ctx.task.error!)
}
})
updateTask.resume()
} catch {
print(error)
}
}
}
Вопрос
Итак, мой основной вопрос: что-то не так смой код обновления? Или это скорее всего бета-ошибка? Есть ли у вас какие-либо предложения по поводу того, что я мог бы попытаться решить?
Весь этот код выше вызывается из DispatchQueue в Controller.swift
. Может ли это быть проблемой?