<p>Really loving golang, I've been a python programmer for a long time, and I have just been completely fed up with how slow the final product usually turns out with it's interpreted and untyped system. So I switched to golang to write my next AI project, a big gamble on my part due to the lack of library support, but in the end it's been good.</p>
<p>Anyway, this might be a good tool for you all, I have needed a sort of memory-acessible, evolvable, programming language for my AI to do self-programming and behavior development. So I started a package within my git called goflow, or just flow for now, and it's modeled heavily on my past with LabVIEW and Tensorflow. It is NOT a neural network library, it is a fully parallelized, function based block library, where blocks have typed inputs and typed outputs and are connected such that data flows between them. The primitive types have been finished, the graph type is in testing, and they are all stackable, so graphs become themselves blocks within new graphs, etc. The only thing I've yet to figure out is the last type, switches, which will control if/then and for/while. I would like to also make a GUI, and a Database save area, as well as a python interface module. Anyway, this is becoming a project all it's own, I'm excited to be done with it so I can work on the evolving AI itself, but I think it is useful enough that I may split it off into it's own git. Only golang could make a project like this so easy. Blocks are all passed map[sting]interface{} as data, so named values, and can be passed a chan bool stop command, and can return an output or error in an output channel. The block executes immediately upon all it's inputs being seen as "ready," and runs in it's own goroutine, which means different branches handle independently, NOTHING runs non-parallel unless it is logically connected. That, IMO, is how all code should run, so I'm very excited about this not only as a language for my AI, but also as a real language.</p>
<p><a href="https://github.com/ryanpeach/goflow" rel="nofollow">https://github.com/ryanpeach/goflow</a></p>
<hr/>**评论:**<br/><br/>raff99: <pre><p>It seems interesting but an example of how you use it would be nice.</p></pre>criticalcontext: <pre><p>Of course, I'm still in development so not a lot of time for tutorials.</p>
<p>In the end, lets say you want a function block for Square root.</p>
<p>Construct it from the blocks library.</p>
<pre><code>sqrtblk = blocks.Sqrt()
</code></pre>
<p>Lets say this is the only function you need, no graph.
You can read from a database that Sqrt accepts a float64 value named "IN" and returns a float64 value named "OUT", or you can access that data by calling:</p>
<pre><code>params_in, params_out := sqrtblk.GetParams()
</code></pre>
<p>params_in and params_out are Parameter structs with methods GetName() and GetType().</p>
<p>So run it like this.</p>
<pre><code>inputs := map[string]interface{}{"IN": float64(2)}
outputs := make(chan map[string]interface{})
stop := make(chan bool)
err := make(chan flow.FlowError)
go sqrtblk.Run(inputs, outputs, stop, err)
</code></pre>
<p>The output and err channel you read from, the stop channel you may write to.</p>
<pre><code>out := (<-outputs)["OUT"]
</code></pre>
<p>Run checks the types of the inputs and the outputs to makes sure everything is implemented correctly.</p>
<p>And now you have the sqrt.</p>
<p>I admit, this is verbose, but here's the deal. Because it's made like this, with the graph structure I've created, which is ran and read from the exact same way (they both use the same interface), you can call long strings of processes. And, an AI program can create graphs intelligently by calling functions like AddNode, AddEdge, RemoveEdge, RemoveNode. I will let you know more once I have implemented that, but that is how it works.</p></pre>boomshroom: <pre><p>Interesting. How would you directly transfer data between blocks? You use a channel on the output, but not the input.</p>
<p>I would encourage you to use less maps and more structured types, though I noticed you seem to allow multiple inputs and outputs that can be each accessed by name. But for the types like int, float, and bool, you can replace them with Go-style enums:</p>
<pre><code>const(
Int = iota
Float
String
Num
Bool
)
</code></pre>
<p>Also, if you're not completely resetting a map, you don't need its pointer; I saw you're passing in a pointer to a map in order to write to it, which is unnecessary.</p>
<p>Finally, maps are not thread safe. If you want everything to be concurrent as it is, you need to use types that are already thread safe (like pointers when not writing, or channels), or use mutexes to lock your data structures.</p></pre>criticalcontext: <pre><p><del>I'm not sure where I'm using any pointers to maps</del>, and I don't need them to be thread safe since they are passed after being completely filled, and are copied between blocks (there is never a situation where two go routines access the same map. Blocks are meant to be run once all inputs are available, so an input channel is unnecessary.</p>
<p>I will read up on enums, I didn't know golang had them!</p>
<p>EDIT: I found the pointers to maps, and your right! I had no idea maps weren't copied, that might require some rethinking. Anyway, it builds now, which is good!</p></pre>criticalcontext: <pre><p>Based on your suggestion, I think I can make some of the maps slices instead, as long as I maintain the order. I'm just trying to prevent unnecessary searching.</p></pre>criticalcontext: <pre><p>I just realized I didn't actually answer your question.</p>
<p>Graph's contain an edge map of type map[Parameter]([]Parameter)</p>
<p>Parameters contain the Address of the block that uses them, their name, and their type.</p>
<p>The goal is for graphs to begin running at initialization all the blocks which are satisfied by the initially passed inputs, by first passing them to all their connected input parameters. All blocks share an output channel, and once any of them pass an output, it's going to pass that output to all connected inputs, and check to see if any new blocks have their inputs fullfilled. This continues in a loop until the output nodes are satisfied for the graph, and then it passes a stop command to all it's children and returns the data on it's own output channel.</p>
<p>All code needs to know is what parameters the graph takes, which are provided, and it will be indistinguishable from a primitive block (which are defined in the blocks package, and must be created by the user).</p>
<p>My goal is that graphs will be immutable and stored in a database such that an AI can log every "try" it has ever made, and use them freely without worrying about instantiating them. I don't quite have this working yet, but it will!</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传