lukaszahradnik / pyneuralogic Goto Github PK
View Code? Open in Web Editor NEWPyNeuraLogic lets you use Python to create Differentiable Logic Programs
Home Page: https://pyneuralogic.readthedocs.io/
License: MIT License
PyNeuraLogic lets you use Python to create Differentiable Logic Programs
Home Page: https://pyneuralogic.readthedocs.io/
License: MIT License
While familiarizing myself with the framework, I defined a Dataset object and added some examples to it. At first, I forgot to add queries before attempting to call evaluator.train(dataset, generator=False)
and received the following NullPointerException
:
Py4JJavaError: An error occurred while calling o176.collect.
: java.lang.NullPointerException
at cz.cvut.fel.ida.neural.networks.structure.building.Neuralizer.getQueryMatchingLiterals(Neuralizer.java:250)
at cz.cvut.fel.ida.neural.networks.structure.building.Neuralizer.supervisedNeuralization(Neuralizer.java:171)
at cz.cvut.fel.ida.neural.networks.structure.building.Neuralizer.neuralize(Neuralizer.java:145)
at cz.cvut.fel.ida.pipelines.pipes.specific.SupervisedNeuralizationPipe.lambda$apply$1(SupervisedNeuralizationPipe.java:38)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:442)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
at py4j.Gateway.invoke(Gateway.java:282)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:238)
at java.base/java.lang.Thread.run(Thread.java:829)
A more descriptive error could be raised in case the dataset does not contain any queries. Since it is an exception triggered by the Java backend, it is possible that it should be handled there. In that case, please let me know and I will move this issue to the backend repo.
No response
No response
When trying to build the model from a template, using the PyG backend, it throws the following error:
Traceback (most recent call last):
File "<input>", line 1, in <module>
model = template.build(Backend.PYG, settings)
File "/usr/local/lib/python3.8/site-packages/neuralogic/core/template.py", line 124, in build
return get_neuralogic_layer(backend)(self.module_list)
File "/usr/local/lib/python3.8/site-packages/neuralogic/nn/__init__.py", line 19, in get_neuralogic_layer
from neuralogic.nn.native.pyg import NeuraLogic
File "/usr/local/lib/python3.8/site-packages/neuralogic/nn/native/pyg.py", line 4, in <module>
from neuralogic.core.settings import Activation, Aggregation
ImportError: cannot import name 'Aggregation' from 'neuralogic.core.settings' (/usr/local/lib/python3.8/site-packages/neuralogic/core/settings/__init__.py)
This is the script that is being used:
from neuralogic.core import Relation, Dataset
from neuralogic.core import Template
from neuralogic.utils.templates import GCNConv, TemplateList
from neuralogic.core import Backend
from neuralogic.core import Settings, Optimizer
dataset = Dataset()
dataset.add_example([
Relation.edge(1, 2), Relation.edge(2, 1), Relation.edge(1, 3),
Relation.edge(3, 1), Relation.edge(2, 3), Relation.edge(3, 2),
Relation.feature(1)[0],
Relation.feature(2)[1],
Relation.feature(3)[-1],
])
template = Template(module_list=TemplateList([
GCNConv(in_channels=5, out_channels=5),
GCNConv(in_channels=5, out_channels=1),
]))
settings = Settings(learning_rate=0.01, optimizer=Optimizer.SGD, epochs=100)
model = template.build(Backend.PYG, settings)
The expected behaviour would be the creation of the model from the specified template.
macOS Monterey Version 12.2.1 (21D62)
python 3.8.12
neuralogic 0.1.3
torch-geometric 2.0.3
No response
As discussed in #47 I was thinking on a previous stage where we can be sure that some logic is applied just to the facts.
As Gus posed it: "prune out the preprocessing subgraph (not just a chain as it is now), and make its end nodes the new fact neurons (hence effectively skipping it in training)."
Doing this outside the logic language, but was dissapointing
No response
Currently, I am implementing Subgraph network rules for GNNs, and I need to operate on edges and create new graphs based on the connectivity of these edges, but I am not aware of any way to do it in this framework at this moment. I think it may be beneficial to add some feature which would allow creation of new nodes based on some given rules.
I would need some way of creating new nodes and graphs based on the rules, for example some code similar to the following would be expected:
Relation.edge_node(V.E) <= Relation.edge(V.X, V.Y) # creates a node for each edge of the original graph
Relation.edge(V.X, V.Y, V.E) <= Relation.edge_node(V.E), Relation.edge(V.X, V.Y) # defines a relation that ties the edge node and its original nodes together
Relation.edge(V.E1, V.E2) <= (Relation.edge(V.X, V.Y, V.E1), Relation.edge(V.X, V.Z, V.E2))# creates edge between the nodes created above
No response
No response
The to_logic_form()
method defined here doesn't seem to consider the 'edge_attr' attribute.
Should't it initialize the edge predicate weights with the values passed to edge_attr? Something in the lines of
Relation.get(edge_name)(int(u), int(v), int(w))[1].fixed() for u, v, w in zip(self.edge_index[0], self.edge_index[1], self.edge_attr[:, 0])
No response
No response
I am trying to train a simple model using the PyNeraLogic framework on the CLUTRR dataset.
However, after creating my Dataset and setting up the Template, I am getting the following error before the first training epoch starts:
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in cz.cvut.fel.ida.neural.networks.computation.training.strategies.PythonTrainingStrategy.learnSamples()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in cz.cvut.fel.ida.neural.networks.computation.training.strategies.trainers.SequentialTrainer$SequentialListTrainer.learnEpoch()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in cz.cvut.fel.ida.neural.networks.computation.training.strategies.trainers.Trainer.learnFromSample()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in cz.cvut.fel.ida.neural.networks.computation.training.strategies.trainers.Trainer.backpropSample()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in cz.cvut.fel.ida.neural.networks.computation.iteration.actions.Backpropagation.backpropagate()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in cz.cvut.fel.ida.neural.networks.computation.iteration.modes.Topologic$TDownVisitor.topdown()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in java.util.ArrayList.get()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in java.util.Objects.checkIndex()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in jdk.internal.util.Preconditions.checkIndex()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in jdk.internal.util.Preconditions.outOfBoundsCheckIndex()
/usr/local/lib/python3.7/dist-packages/_jpype.cpython-37m-x86_64-linux-gnu.so in jdk.internal.util.Preconditions.outOfBounds()
Exception: Java Exception
The above exception was the direct cause of the following exception:
java.lang.IndexOutOfBoundsException Traceback (most recent call last)
[<ipython-input-96-4b77102c2769>](https://localhost:8080/#) in <module>()
5 average_losses = []
6
----> 7 for i, current_total_loss, number_of_samples in enumerate(evaluator.train(dataset)):
8 print(f"epoch: {i}")
9 clear_output(wait=True)
[/usr/local/lib/python3.7/dist-packages/neuralogic/nn/evaluators/java.py](https://localhost:8080/#) in _train()
42 def _train():
43 for _ in range(epochs):
---> 44 results, total_len = self.neuralogic_model(None, True)
45 yield sum(result[2] for result in results), total_len
46 if dataset is not None:
[/usr/local/lib/python3.7/dist-packages/neuralogic/nn/java.py](https://localhost:8080/#) in __call__(self, samples, train, auto_backprop, epochs)
80
81 if samples is None:
---> 82 results = self.strategy.learnSamples(epochs)
83 deserialized_results = json.loads(str(results))
84
java.lang.IndexOutOfBoundsException: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 9
My Template is based on this example.
One sample graph in the CLUTRR dataset looks as follows
story: [('Donald', 'father', 'Michael'), ('Michael', 'sister', 'Dorothy')]
target: ('Donald', 'aunt', 'Dorothy')
The input triplets and the target pair (Donald, Dorothy)
are given and the task is to predict their relationship (aunt
), it is thus an R-way classification task where R is the total number of relations (such as aunt, father, ...).
Below you can see the dataset creation process
for i in range(len(data.train)):
sample = data.train[i]
query = Relation.predict(*sample.target)
persons = set(p for p, _, _ in sample.story)
persons.update(p for _, _, p in sample.story)
example = list(itertools.chain(
(Relation.edge(u, r, v) for u, r, v in sample.story),
(Relation.rel(r) for _, r, _ in sample.story + [sample.target]),
(Relation.person(p) for p in persons)
))
dataset.add_example(example)
dataset.add_query(query)
This results in a dataset that looks like this:
Query:
predict(Donald, aunt, Dorothy).
Example:
['edge(Donald, father, Michael)', 'edge(Michael, sister, Dorothy)', 'rel(father)', 'rel(sister)', 'rel(aunt)', 'person(Dorothy)', 'person(Donald)', 'person(Michael)']
The template definition is equivalent to the definition of the example template mentioned above, but it is rewritten to the PyNeuraLogic syntax. It looks as follows:
template = Template()
# {3} @embed_nation(X) :- nation(X).
# {3} @embed_rel(X) :- rel(X).
template.add_rules([
(R.person_embed(V.A)[3,] <= R.person(V.A)),
(R.rel_embed(V.B)[3,] <= R.rel(V.B))
])
# embed_nat1(X) :- {3,3} embed_rel(R), {3,3} embed_nation(Y), {3} r(X,R,Y).
template.add_rule(
R.person_embed1(V.X) <= (R.rel_embed(V.R)[3, 3], R.person_embed(V.Y)[3, 3], R.edge(V.X, V.R, V.Y)[3,])
)
# embed_nat2(Y) :- {3,3} embed_nation(X), {3,3} embed_rel(R), {3} r(X,R,Y).
template.add_rule(
R.person_embed2(V.Y) <= (R.person_embed(V.X)[3, 3], R.rel_embed(V.R)[3, 3], R.edge(V.X, V.R, V.Y)[3,])
)
# {1,3} predict(X,R,Y) :- {3,3} embed_nat1(X), {3,3} embed_nat2(Y), {3,3} embed_rel(R).
template.add_rule(
R.predict(V.X, V.R, V.Y)[1, 3] <= (R.person_embed1(V.X)[3, 3], R.person_embed2(V.Y)[3, 3], R.rel_embed(V.R)[3, 3])
)
The evaluator definition and part of training loop can be seen here. The last line triggers the exception.
settings = Settings(optimizer=Optimizer.ADAM, epochs=120, learning_rate=0.001, error_function=ErrorFunction.SQUARED_DIFF)
evaluator = get_evaluator(template, Backend.JAVA, settings)
for i, current_total_loss, number_of_samples in enumerate(evaluator.train(dataset)):
...
calling evaluator.train(dataset)
should yield (current_total_loss, number_of_samples)
correctly instead of raising an exception
Google Colab (Python 3.6)
Also, are there any other fundamental issues with the way I defined the dataset and architecture for this particular task? I am still trying to wrap my head around the way this framework works and how to rewrite PyG code to neuralogic language.
Thank you!
As described in discussion #59, I would like to visualize the importance of the nodes for the infered prediction.
It would be best to have a way to get the node for some defined predicate, and extract the gradients and weights values.
No response
No response
From the This example notebook Visualization.ipynb
:
Call to neuralogic.utils.visualize.draw_model
function, draw_model(model)
, results in the following error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-59797e1249fd> in <module>
7 model = template.build(Backend.JAVA, Settings())
8
----> 9 draw_model(model)
...\lib\site-packages\neuralogic\utils\visualize\__init__.py in draw_model(model, filename, draw_ipython, img_type, value_detail, *args, **kwargs)
93 template_drawer = get_template_drawer(get_drawing_settings(img_type=img_type, value_detail=value_detail))
94
---> 95 return draw(template_drawer, template, filename, draw_ipython, img_type, *args, **kwargs)
96
97
...\lib\site-packages\neuralogic\utils\visualize\__init__.py in draw(drawer, obj, filename, draw_ipython, img_type, *args, **kwargs)
55 return
56
---> 57 data = bytes(drawer.drawIntoBytes(obj))
58
59 if draw_ipython:
TypeError: cannot convert 'NoneType' object to bytes
Similarly, adding a filename to the call (draw_model(model, 'img.png')
, see code snippets below) results in a NullPointerException:
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
...\lib\site-packages\_jpype.cp38-win_amd64.pyd in cz.cvut.fel.ida.drawing.Drawer.drawIntoFile()
...\lib\site-packages\_jpype.cp38-win_amd64.pyd in cz.cvut.fel.ida.drawing.GraphViz.writeImageToFile()
~\Anaconda3\envs\bakalarka\lib\site-packages\_jpype.cp38-win_amd64.pyd in java.io.FileOutputStream.write()
Exception: Java Exception
The above exception was the direct cause of the following exception:
java.lang.NullPointerException Traceback (most recent call last)
<ipython-input-8-91eec29cdcf5> in <module>
7 model = template.build(Backend.JAVA, Settings())
8
----> 9 draw_model(model, 'img.png')
...\lib\site-packages\neuralogic\utils\visualize\__init__.py in draw_model(model, filename, draw_ipython, img_type, value_detail, *args, **kwargs)
93 template_drawer = get_template_drawer(get_drawing_settings(img_type=img_type, value_detail=value_detail))
94
---> 95 return draw(template_drawer, template, filename, draw_ipython, img_type, *args, **kwargs)
96
97
...\lib\site-packages\neuralogic\utils\visualize\__init__.py in draw(drawer, obj, filename, draw_ipython, img_type, *args, **kwargs)
51 def draw(drawer, obj, filename: Optional[str] = None, draw_ipython=True, img_type="png", *args, **kwargs):
52 if filename is not None:
---> 53 drawer.drawIntoFile(obj, os.path.abspath(filename))
54
55 return
java.lang.NullPointerException: java.lang.NullPointerException
I have come across this error in my own example codes, but it is enough to run the Visualization.ipynb
notebook, concretely:
from neuralogic.utils.visualize import draw_model
from neuralogic.utils.data import XOR_Vectorized
from neuralogic.core import Settings, Backend
template, dataset = XOR_Vectorized()
model = template.build(Backend.JAVA, Settings())
draw_model(model)
For the NullPointerException, I used:
from neuralogic.utils.visualize import draw_model
from neuralogic.utils.data import XOR_Vectorized
from neuralogic.core import Settings, Backend
template, dataset = XOR_Vectorized()
model = template.build(Backend.JAVA, Settings())
draw_model(model, 'img.png')
I should be able to visualize the model.
No response
No response
I am trying to test a model using evaluator.test(test_dataset)
, but I am getting the following exception:
[<ipython-input-58-4d4659b17081>](https://localhost:8080/#) in test(test_dataset)
2 def test(test_dataset: Dataset) -> float:
3 correct = 0
----> 4 for y, y_hat in evaluator.test(test_dataset):
5 # print(f"Expected: {y}, Predicted: {round(y_hat)} ({y_hat})")
6 if round(y) == round(y_hat):
[/usr/local/lib/python3.7/dist-packages/neuralogic/nn/evaluators/java.py](https://localhost:8080/#) in _test()
62 for sample in dataset.samples:
63 result = self.neuralogic_model(sample, False)
---> 64 yield result.target(), result.output()
65
66 if generator:
[/usr/local/lib/python3.7/dist-packages/neuralogic/nn/java.py](https://localhost:8080/#) in target(self)
24
25 def target(self) -> float:
---> 26 return self.loss.getTarget().value
27
28
AttributeError: 'cz.cvut.fel.ida.algebra.values.VectorValue' object has no attribute 'value'
I have my dataset and template set up as discussed in our recent discussion (I am using onehot encoding for the class labels). I am also using the following settings
settings = Settings(optimizer=Optimizer.ADAM, epochs=n_epochs, learning_rate=0.001, error_function=ErrorFunction.CROSSENTROPY)
I am able to successfully run the training loop, but as soon as I want to test the model I receive the AttributeError exception.
I should be able to test the model without an error.
Google Colab
No response
As from the title, saving a state_dict
with torch causes an error
_pickle.PicklingError: Can't pickle <java class 'java.lang.String'>: attribute lookup java.lang.String on jpype._jstring failed
Assuming torch is loaded and we have a (trained) model initialised by model = template.build(settings)
, the error occurs with the following code
state_dict = model.state_dict()
torch.save(state_dict, save_file)
The code does not cause a pickling error.
No response
I have an easy workaround which does not seem to cause any issues by converting the strings into Python strings
state_dict = model.state_dict()
state_dict["weight_names"] = {k: str(v) for k, v in state_dict["weight_names"].items()}
torch.save(state_dict, save_file)
I don't seem to have any unexpected behaviour while doing this, e.g. loaded models have the same predictions.
On Windows, when using the Template.draw
method, I get the following error even though I have GraphViz installed and added to the Path (I tried out both System and User path variables):
Exception Traceback (most recent call last)
File Drawer.java:80, in cz.cvut.fel.ida.drawing.Drawer.drawIntoFile()
Exception: Java Exception
The above exception was the direct cause of the following exception:
java.lang.NullPointerException Traceback (most recent call last)
File ...\neuralogic\utils\visualize\__init__.py:75, in draw(drawer, obj, filename, show, img_type, *args, **kwargs)
74 try:
---> 75 drawer.drawIntoFile(obj, os.path.abspath(filename))
76 except jpype.java.lang.NullPointerException as e:
java.lang.NullPointerException: java.lang.NullPointerException: Cannot invoke "cz.cvut.fel.ida.algebra.weights.Weight.toString(java.text.NumberFormat)" because the return value of "cz.cvut.fel.ida.logic.constructs.template.components.WeightedRule.getWeight()" is null
...
Exception Traceback (most recent call last)
File ...\neuralogic\core\template.py:159, in Template.draw(self, filename, show, img_type, value_detail, graphviz_path, model, *args, **kwargs)
157 if model is None:
158 model = self.build(Settings())
--> 159 return draw_model(model, filename, show, img_type, value_detail, graphviz_path, *args, **kwargs)
File ...\neuralogic\utils\visualize\__init__.py:153, in draw_model(model, filename, show, img_type, value_detail, graphviz_path, *args, **kwargs)
150 template = model.template
151 template_drawer = get_template_drawer(get_drawing_settings(img_type, value_detail, graphviz_path))
--> 153 return draw(template_drawer, template, filename, show, img_type, *args, **kwargs)
File ...\neuralogic\utils\visualize\__init__.py:77, in draw(drawer, obj, filename, show, img_type, *args, **kwargs)
75 drawer.drawIntoFile(obj, os.path.abspath(filename))
76 except jpype.java.lang.NullPointerException as e:
---> 77 raise Exception(
78 "Drawing raised NullPointerException. Try to install GraphViz (https://graphviz.org/download/) on "
79 "your Path or specify the path via the `graphviz_path` parameter"
80 ) from e
82 return
84 data = drawer.drawIntoBytes(obj)
Exception: Drawing raised NullPointerException. Try to install GraphViz (https://graphviz.org/download/) on your Path or specify the path via the `graphviz_path` parameter
The exception seems to be at least misleading, as can be seen from the two examples below.
While the following small example works just fine:
from neuralogic.core import Template, R, V
feature_dim = 1
hidden_dim = 3
output_dim = 1
template = Template()
template += (R.layer_1(V.X)[hidden_dim, feature_dim] <= (R.feature(V.Y), R._edge(V.Y, V.X)))
template += (R.predict[output_dim, hidden_dim] <= R.layer_1(V.X))
# {3, 1} layer_1(X) :- feature(Y), *edge(Y, X).
# {1, 3} predict :- layer_1(X).
template.draw('fig.png')
possibly suggesting the problem is not with Path or Graphviz, the next example throws the error above:
from neuralogic.core import Template
from neuralogic.nn.module import GCNConv
feature_dim = 1
hidden_dim = 3
output_dim = 1
template = Template()
template.add_module(
GCNConv(in_channels=feature_dim, out_channels=hidden_dim, output_name="h0", feature_name="node", edge_name="edge")
)
# h0__edge(I, I).
# h0__edge(I, J) :- edge(I, J). [transformation=identity]
# h0__edge/2 [transformation=identity]
# h0__edge_count(I, J) :- h0__edge(J, X). [transformation=identity, aggregation=count]
# h0__edge_count(I, J) :- h0__edge(I, X). [transformation=identity, aggregation=count]
# h0__edge_count/2 [transformation=inverse, combination=product]
# {3, 1} h0(I) :- node(J), h0__edge(J, I), sqrt(h0__edge_count(J, I)). [transformation=identity, combination=product, aggregation=sum]
# h0/1 [transformation=identity]
template.draw('fig.png') # <-- throws an error
Drawing the graph representation of the template.
Windows 11 Home 10.0.22631
Python 3.12.3
neuralogic 0.7.11
torch 2.2.2
torch-geometric 2.5.2
No response
I am trying to implement a recursive path rule on the Mutagenesis dataset, and the rules are defined as below:
template.add_rules([
(R.bond_embed(V.B)[3,] <= R.get(bond)(V.B)) for bond in ["b_1", "b_2", "b_3", "b_4", "b_5", "b_7"]
])
template += R.path(V.X, V.Y) <= (R.bond(V.X, V.Y, V.B), R.bond_embed(V.B)[3, 3])
template += R.path(V.X, V.Y) <= (R.bond(V.X, V.Z, V.B), R.bond_embed(V.B)[3, 3], R.path(V.Z, V.Y)[3, 3])
The problem is that when I have weights in the second rule, it cannot build the dataset and I get the following error:
Without weights, it does not produce any errors.
Make a template with these rules and try to build the dataset.
The dataset can be built with the given weighted rules.
No response
No response
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.