package fehu
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Reinforcement learning framework for OCaml
Install
dune-project
Dependency
Authors
Maintainers
Sources
raven-1.0.0.alpha2.tbz
sha256=93abc49d075a1754442ccf495645bc4fdc83e4c66391ec8aca8fa15d2b4f44d2
sha512=5eb958c51f30ae46abded4c96f48d1825f79c7ce03f975f9a6237cdfed0d62c0b4a0774296694def391573d849d1f869919c49008acffca95946b818ad325f6f
doc/src/fehu.visualize/sink.ml.html
Source file sink.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163open Fehu type t = { push : Render.t -> unit; close : unit -> unit } let custom ?(close = fun () -> ()) push = { push; close } let noop = custom (fun _ -> ()) let push sink frame = sink.push frame let close sink = sink.close () let string_of_status = function | Unix.WEXITED code -> Printf.sprintf "exit status %d" code | Unix.WSIGNALED signal -> Printf.sprintf "signal %d" signal | Unix.WSTOPPED signal -> Printf.sprintf "stopped (signal %d)" signal let ensure_ffmpeg () = match Unix.system "ffmpeg -version >/dev/null 2>&1" with | Unix.WEXITED 0 -> () | _ -> invalid_arg "ffmpeg executable not found in PATH" let rec mkdir_p dir = if dir = "" || dir = "." || dir = Filename.dir_sep then () else if Sys.file_exists dir then () else ( mkdir_p (Filename.dirname dir); try Unix.mkdir dir 0o755 with Unix.Unix_error (Unix.EEXIST, _, _) -> ()) type ffmpeg_state = { fps : int; path : string; extra_args : string list; mutable channel : out_channel option; mutable width : int; mutable height : int; } let build_command state width height = let extra = match state.extra_args with | [] -> "" | args -> " " ^ String.concat " " args in Printf.sprintf "ffmpeg -loglevel error -y -f rawvideo -pix_fmt rgb24 -r %d -s %dx%d -i \ -%s %s" state.fps width height extra (Filename.quote state.path) let start_process (state : ffmpeg_state) (image : Render.image) = mkdir_p (Filename.dirname state.path); let cmd = build_command state image.width image.height in let channel = try Unix.open_process_out cmd with Unix.Unix_error (err, _, _) -> invalid_arg (Printf.sprintf "Failed to launch ffmpeg: %s" (Unix.error_message err)) in state.channel <- Some channel; state.width <- image.width; state.height <- image.height; channel let ensure_channel (state : ffmpeg_state) (image : Render.image) = match state.channel with | Some channel -> if image.width <> state.width || image.height <> state.height then invalid_arg "ffmpeg sink expects consistent frame dimensions"; channel | None -> start_process state image let close_state state = match state.channel with | None -> () | Some channel -> flush channel; let status = Unix.close_process_out channel in state.channel <- None; if status <> Unix.WEXITED 0 then invalid_arg (Printf.sprintf "ffmpeg exited abnormally (%s)" (string_of_status status)) let create_ffmpeg_sink ~fps ~path ~extra_args = ensure_ffmpeg (); let state = { fps; path; extra_args; channel = None; width = 0; height = 0 } in let push frame = match frame with | Render.None -> () | Render.Image image -> let channel = ensure_channel state image in let bytes = Utils.rgb24_bytes_of_image image in output_bytes channel bytes; flush channel | Render.Text _ | Render.Svg _ -> invalid_arg "ffmpeg sink expects image frames" in let close () = close_state state in custom ~close push let ffmpeg ?(fps = 30) ~path () = create_ffmpeg_sink ~fps ~path ~extra_args:[ "-an"; "-vcodec"; "libx264"; "-pix_fmt"; "yuv420p" ] let gif ?(fps = 30) ~path () = create_ffmpeg_sink ~fps ~path ~extra_args:[ "-f"; "gif" ] let log_to_wandb ~project ~run ~path ~fps = let script_path = Filename.temp_file "fehu-wandb" ".py" in let python = Option.value (Sys.getenv_opt "FEHU_WANDB_PYTHON") ~default:"python3" in let write_script () = let oc = open_out script_path in Fun.protect ~finally:(fun () -> close_out oc) (fun () -> Printf.fprintf oc "import wandb\n\ run = wandb.init(project=%S, name=%S, reinit=True)\n\ run.log({'rollout': wandb.Video(%S, fps=%d)})\n\ run.finish()\n" project run path fps) in Fun.protect (fun () -> write_script (); match Unix.system (Printf.sprintf "%s %s" python (Filename.quote script_path)) with | Unix.WEXITED 0 -> () | status -> invalid_arg (Printf.sprintf "wandb logging failed (%s). Ensure wandb is installed and you \ are logged in." (string_of_status status))) ~finally:(fun () -> if Sys.file_exists script_path then Sys.remove script_path) let wandb ?(fps = 30) ~project ~run () = let temp_path = Filename.temp_file "fehu-wandb" ".mp4" in let inner = ffmpeg ~fps ~path:temp_path () in let push frame = push inner frame in let close () = Fun.protect ~finally:(fun () -> if Sys.file_exists temp_path then Sys.remove temp_path) (fun () -> close inner; log_to_wandb ~project ~run ~path:temp_path ~fps) in custom ~close push let with_sink create f = let sink = create () in Fun.protect ~finally:(fun () -> close sink) (fun () -> f sink) let with_ffmpeg ?fps ~path f = with_sink (fun () -> ffmpeg ?fps ~path ()) f let with_gif ?fps ~path f = with_sink (fun () -> gif ?fps ~path ()) f let with_wandb ?fps ~project ~run f = with_sink (fun () -> wandb ?fps ~project ~run ()) f
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>