Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Column-wise operations in Learning Networks #271

Closed
petrostat13 opened this issue Oct 11, 2019 · 5 comments
Closed

Column-wise operations in Learning Networks #271

petrostat13 opened this issue Oct 11, 2019 · 5 comments

Comments

@petrostat13
Copy link

Is there a way to perform column-wise operations to nodes of a learning network?

One can use FeatureSelector to manipulate the input source, but I couldn't do the same with the target source.

For example, let's say I want to train 2 models on the same input data but with different target variables. So if I define the target source as a 2-column Array, how do I separate the columns inside the network? Or is there a way to merge specific columns of different nodes into a new node? In general, is there a way to manipulate columns of nodes in such a network?

Thank you!

@ablaom
Copy link
Member

ablaom commented Oct 11, 2019

Good question. Answer is yes.

You can think as a node for a proxy for data. Anything you can do to data you can do to a node that is a proxy for that kind of data, using the node method; do ?node for details. Here's a DataFrame example:

julia> X = DataFrame(rand(10,3))
10×3 DataFrame
│ Row │ x1       │ x2        │ x3         │
│     │ Float64  │ Float64   │ Float64    │
├─────┼──────────┼───────────┼────────────┤
│ 10.5184050.8694670.676809   │
│ 20.166940.3819580.840221   │
│ 30.8328590.2859730.166679   │
│ 40.323790.1834280.00638633 │
│ 50.245990.2825920.539567   │
│ 60.9802810.9452390.267164   │
│ 70.5448120.01052230.480417   │
│ 80.749890.4445390.64379    │
│ 90.0413120.6067450.100776   │
│ 100.1198280.9303620.419426   │

julia> Xs = source(X)
Source{:input} @ 309

julia> Y = node(df -> df[:, [:x1, :x2]], Xs)  # pick off multiple columns
Node @ 184 = #15(3…09)

julia> Y()
10×2 DataFrame
│ Row │ x1       │ x2        │
│     │ Float64  │ Float64   │
├─────┼──────────┼───────────┤
│ 10.5184050.869467  │
│ 20.166940.381958  │
│ 30.8328590.285973  │
│ 40.323790.183428  │
│ 50.245990.282592  │
│ 60.9802810.945239  │
│ 70.5448120.0105223 │
│ 80.749890.444539  │
│ 90.0413120.606745  │
│ 100.1198280.930362  │

julia> y = node(df -> df.x3, Xs) # pick off single column
Node @ 150 = #17(3…09)

julia> y()
10-element Array{Float64,1}:
 0.6768089324906859   
 0.8402212806559988   
 0.16667879796758434  
 0.0063863346857631065
 0.5395665542748085   
 0.2671635276250435   
 0.48041697446815457  
 0.6437900249878024   
 0.10077583630960008  
 0.41942618943917687  

To do the same thing for generic tables (which include DataFrames) you could use the built-in selectcols method (do ?selectcols for possible arguments):

julia> Y = node(table->selectcols(table, [:x1, :x2]), Xs)
Node @ 898 = #21(3…09)

julia> Y()
10×2 DataFrame
│ Row │ x1       │ x2        │
│     │ Float64  │ Float64   │
├─────┼──────────┼───────────┤
│ 10.5184050.869467  │
│ 20.166940.381958  │
│ 30.8328590.285973  │
│ 40.323790.183428  │
│ 50.245990.282592  │
│ 60.9802810.945239  │
│ 70.5448120.0105223 │
│ 80.749890.444539  │
│ 90.0413120.606745  │
│ 100.1198280.930362

(Maybe we should provide a version of selectcols overloaded for nodes out-of-the-box?)

To merge columns, you can do things like this:

julia> t(v1, v2) = (a=v1, b=v2)  # define a function to put two vectors into a column table
t (generic function with 1 method)

julia> t(rand(3), [1, 2, 3])
(a = [0.0223417, 0.723267, 0.511597],
 b = [1, 2, 3],)

julia> as = source(rand(3))
Source{:input} @ 165

julia> bs = source([1,2,3])
Source{:input} @ 288

julia> X = node(t, as, bs)
┌ Warning: A node referencing multiple origins when called has been defined:
│ MLJ.Source{:input}[Source{:input} @ 165, Source{:input} @ 288]. 
└ @ MLJ ~/Dropbox/Julia7/MLJ/MLJ/src/networks.jl:197
Node @ 100 = t(165, 288)

julia> X()
(a = [0.750533, 0.4004, 0.808384],
 b = [1, 2, 3],)

(You can ignore the warning here.)

Does this answer your question?

@petrostat13
Copy link
Author

Thank you very much for your help, greatly appreciated!

@petrostat13
Copy link
Author

@ablaom sorry for the repeated questions, but I have another one.

Let's say I want to first pre-train and then fine-tune a neural net. Thus, in the the training phase of the learning network, the training data is split into 'pre' and 'fine'. Model 'NNpre' is trained and the weights are saved. Then model 'NNfine' is trained with initial weights equal to the previously saved weights. All of the above are shown in the diagram below.

The problem I have is the following: If I do not include any 'predict' nodes after 'NNpre' or 'NNfine', they are just not trained, because their respective nodal machines do not lead to the final node. However, if I include 'predict' nodes, the test data will also be split into 'pre' and 'fine' (?). The general question is if there is a way to separate the flow of information between the training and predicting phases. Could for example some nodes be activated only during training and not predicting and vice versa?

Thanks again!

network

@ablaom
Copy link
Member

ablaom commented Oct 21, 2019

@petrostat13 Thanks for the interesting use-case.

I don't immediately see a way for the existing API to wrap everything you want in a single composite model. As I understand it, what you want to do is update the learned parameters of some model (a self-tuning neural-network) based on new data. That is, you want online learning, which isn't currently supported, but hopefully will be at some point (#60).

@ablaom ablaom mentioned this issue Oct 21, 2019
6 tasks
@ablaom
Copy link
Member

ablaom commented Oct 22, 2019

Re the original comment: selectcols is now overloaded for nodes (MLJ 0.5.1):

julia> using DataFrames, MLJ

julia> X = source(DataFrame(rand(2,3)))
Source{:input} @ 649

julia> X()
2×3 DataFrame
│ Row │ x1       │ x2       │ x3       │
│     │ Float64  │ Float64  │ Float64  │
├─────┼──────────┼──────────┼──────────┤
│ 10.235620.9145970.414423 │
│ 20.5296330.2803830.641822 │

julia> v = selectcols(X, :x1)
Node @ 670 = #40(6…49)

julia> v()
2-element Array{Float64,1}:
 0.2356195529795364
 0.5296331600177344

julia> Xsmall = selectcols(X, 1:2)
Node @ 111 = #40(6…49)

julia> Xsmall()
2×2 DataFrame
│ Row │ x1       │ x2       │
│     │ Float64  │ Float64  │
├─────┼──────────┼──────────┤
│ 10.235620.914597 │
│ 20.5296330.280383

@ablaom ablaom closed this as completed Oct 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants