JsonProvider дает мне разные типы, которые я не могу объединить - PullRequest
0 голосов
/ 12 сентября 2018

Я использую провайдер типа JSON для загрузки созданного мной файла JSON.Минимальный ввод для провайдера типов выглядит следующим образом:

{
  "conv1": {
    "weight": {
      "shape": [ 64, 3, 7, 7 ],
      "data": [ 1e-30, -0.01077061053365469 ]
    }
  },
  "bn1": {
    "eps": 1e-05,
    "weight": {
      "shape": [ 64 ],
      "data": [ 1e-30, 0.2651672959327698 ]
    },
    "bias": {
      "shape": [ 64 ],
      "data": [ 1e-30, 0.24643374979496002 ]
    }
  }
}

Хотя обе детали weight имеют одинаковую форму и тип, провайдер типов дает мне два разных, но эквивалентных типа:

type Weight =
    inherit IJsonDocument
    new : shape: int [] * data: float [] -> Weight
    member Data : float []
    member JsonValue: JsonValue
    member Shape: int []

и

type Weight2 =
    inherit IJsonDocument
    new : shape: int [] * data: float [] -> Weight2
    member Data : float []
    member JsonValue: JsonValue
    member Shape: int []

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

Мой первый подход состоял в использовании перегрузки:

type Tensor = {
    Data:single[]
    Shape:int list
} with
    static member Unify1 (w:NN.Weight) = { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }
    static member Unify1 (w:NN.Weight2) = { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }

Ошибка FS0438 Повторяющийся метод.Метод Unify1 имеет то же имя и сигнатуру, что и другой метод в типе Tensor после удаления кортежей, функций, единиц измерения и / или предоставленных типов.

Затем я попробовал ручное тестирование типовнапример:

let unify2 (o:obj) =
    match o with
    | :? NN.Weight as w -> { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }
    | :? NN.Weight2 as w -> { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }
    | _ -> failwith "pattern oops"

Этот вариант не компилируется, потому что

Ошибка FS3062 Этот тип теста с предоставленным типом JsonProvider<...>.Weight не разрешен, потому что этопредоставленный тип будет удален до Runtime.BaseTypes.IJsonDocument во время выполнения.

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

1 Ответ

0 голосов
/ 12 сентября 2018

Я согласен, что выведенный тип не так хорош, как мог бы быть. У поставщика типов XML есть статический параметр Global, который объединяет элементы XML по всему документу на основе их имени - поэтому, предположительно, поставщик JSON может сделать что-то подобное (но это более сложно, потому что мы бы должны идентифицировать, что две записи являются «одинаковыми» на основе либо только их полей, либо метки, используемой в родительском элементе ...). Если вы заинтересованы в участии в F # Data, пожалуйста, откройте вопрос, чтобы обсудить это!

Между тем, я думаю, что разумный обходной путь - это получить базовый JsonValue и затем обернуть его обратно в предоставленный тип Weight. Это будет работать для обеих weight записей, поскольку они имеют одинаковые поля:

type NN = JsonProvider<"""{ ... }""">

let processWeight (js:JsonValue) = 
  let w = NN.Weight(js)
  w.Data, w.Shape

let nn = NN.GetSample()
nn.Conv1.Weight.JsonValue |> processWeight
nn.Bn1.Weight.JsonValue |> processWeight

Немного причудливее было бы использовать статические ограничения-члены для доступа к свойству JsonValue в функции processWeight (чтобы вы могли просто вызвать nn.Conv1.Weight |> processWeight), но я не хотел усложнять пример .

...