00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
#include "UnfoldedFuncVariable.h"
00044
00045
00046
00047
namespace PLearn {
00048
using namespace std;
00049
00050
00051
00054
PLEARN_IMPLEMENT_OBJECT(UnfoldedFuncVariable,
"Variable that puts in the rows of its output matrix the value\n"
00055
"of a Func evaluated on each row of an input matrix.\n",
00056
"The input_matrix and output matrix have n_unfold rows. A separate propagation path\n"
00057
"is created that maps (using the Func as a template) each input row to each output row.\n"
00058
"The parents of this variable include the non-input parents of the Func.\n");
00059
00060 UnfoldedFuncVariable::UnfoldedFuncVariable()
00061 :
transpose(0)
00062 {}
00063
00064 UnfoldedFuncVariable::UnfoldedFuncVariable(
Var inputmatrix,
Func the_f,
bool the_transpose)
00065 :
inherited(
nonInputParentsOfPath(the_f->inputs,the_f->outputs) & inputmatrix,
00066 the_transpose ? the_f->outputs[0]->length()*the_f->outputs[0]->width() : inputmatrix->length(),
00067 the_transpose ? inputmatrix->width() : the_f->outputs[0]->length()*the_f->outputs[0]->width()),
00068 input_matrix(inputmatrix),
00069 f(the_f),
00070
transpose(the_transpose)
00071 {
00072
build();
00073 }
00074
00075 void UnfoldedFuncVariable::build()
00076 {
00077 inherited::build();
00078
build_();
00079 }
00080
00081 void UnfoldedFuncVariable::build_()
00082 {
00083
if (
f) {
00084
if(
f->outputs.size()!=1)
00085
PLERROR(
"In UnfoldedFuncVariable: function must have a single variable output (maybe you can vconcat the vars into a single one prior to calling sumOf, if this is really what you want)");
00086
f->inputs.setDontBpropHere(
true);
00087
int n_unfold =
transpose ?
input_matrix->
width() :
input_matrix->
length();
00088
inputs.
resize(n_unfold);
00089
outputs.
resize(n_unfold);
00090
f_paths.
resize(n_unfold);
00091
for (
int i=0;i<n_unfold;i++)
00092 {
00093
inputs[i].
resize(
f->inputs.size());
00094
for (
int j = 0; j <
f->inputs.size(); j++) {
00095
inputs[i][j] =
Var(
f->inputs[j]->length(),
f->inputs[j]->width());
00096 }
00097
outputs[i] =
f(
inputs[i])[0];
00098
f_paths[i] =
propagationPath(
inputs[i],
outputs[i]);
00099 }
00100 }
00101 }
00102
00103 void UnfoldedFuncVariable::declareOptions(
OptionList& ol)
00104 {
00105
declareOption(ol,
"f", &UnfoldedFuncVariable::f, OptionBase::buildoption,
00106
" Func that is replicated for each element of the 'bag' taken from the VMat.");
00107
00108
declareOption(ol,
"input_matrix", &UnfoldedFuncVariable::input_matrix, OptionBase::buildoption,
00109
" Var that contains the data, with multiple consecutive rows forming one bag.\n");
00110
00111
declareOption(ol,
"transpose", &UnfoldedFuncVariable::transpose, OptionBase::buildoption,
00112
" If set to 1, then instead puts in the columns of the output matrix the values\n"
00113
" of f at the columns of the input matrix.");
00114
00115 inherited::declareOptions(ol);
00116 }
00117
00118
00119 void UnfoldedFuncVariable::recomputeSize(
int& l,
int& w)
const
00120
{
00121
if (
f &&
f->outputs.size()) {
00122 w =
f->outputs[0]->length()*
f->outputs[0]->width();
00123
if (
transpose) {
00124 l = w;
00125 w =
input_matrix->
width();
00126 }
else {
00127 l =
input_matrix->
length();
00128 }
00129 }
else
00130 l = w = 0;
00131 }
00132
00133
00134 void UnfoldedFuncVariable::makeDeepCopyFromShallowCopy(map<const void*, void*>& copies)
00135 {
00136 NaryVariable::makeDeepCopyFromShallowCopy(copies);
00137
deepCopyField(
input_matrix, copies);
00138
deepCopyField(
f, copies);
00139
deepCopyField(
inputs, copies);
00140
deepCopyField(
outputs, copies);
00141
deepCopyField(
f_paths, copies);
00142 }
00143
00144
00145 void UnfoldedFuncVariable::fprop()
00146 {
00147
int n_unfold =
transpose ?
input_matrix->
width() :
input_matrix->
length();
00148
for (
int i=0;i<n_unfold;i++) {
00149
if (
transpose) {
00150
Vec tmp =
input_matrix->matValue.
column(i).toVecCopy();
00151
inputs[i] << tmp;
00152 }
else {
00153
inputs[i] <<
input_matrix->matValue(i);
00154 }
00155
f_paths[i].fprop();
00156
if (
transpose) {
00157 matValue.
column(i) <<
outputs[i]->value;
00158 }
else {
00159 matValue(i) <<
outputs[i]->value;
00160 }
00161 }
00162 }
00163
00164
00165 void UnfoldedFuncVariable::bprop()
00166 {
00167
int n_unfold =
transpose ?
input_matrix->
width() :
input_matrix->
length();
00168
for (
int i=0;i<n_unfold;i++)
00169 {
00170
f_paths[i].clearGradient();
00171
if (
transpose) {
00172
Vec tmp = matGradient.
column(i).toVecCopy();
00173
outputs[i]->gradient << tmp;
00174 }
else {
00175
outputs[i]->gradient << matGradient(i);
00176 }
00177
f_paths[i].bprop();
00178 }
00179 }
00180
00181
00182 void UnfoldedFuncVariable::printInfo(
bool print_gradient)
00183 {
00184
int n_unfold =
transpose ?
input_matrix->
width() :
input_matrix->
length();
00185
for (
int i=0;i<n_unfold;i++)
00186
f_paths[i].printInfo(print_gradient);
00187 cout <<
info() <<
" : " <<
getName() <<
"[" << (
void*)
this <<
"]"
00188 <<
"(input_matrix=" << (
void*)
input_matrix <<
" ";
00189
for(
int i=0; i<n_unfold; i++) cout << (
void*)
outputs[i] <<
" ";
00190 cout <<
") = " << value;
00191
if (print_gradient) cout <<
" gradient=" << gradient;
00192 cout <<
endl;
00193 }
00194
00195
00196 }
00197
00198