Skip to content

Commit fb8d50c

Browse files
author
Yusuke Sugomori
committed
RBM c
1 parent 4927055 commit fb8d50c

File tree

4 files changed

+262
-4
lines changed

4 files changed

+262
-4
lines changed

c/LogisticRegression.h

-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#ifndef LOGISTICREGRESSION_H
22
#define LOGISTICREGRESSION_H
33

4-
54
typedef struct {
65
int N;
76
int n_in;
@@ -16,6 +15,4 @@ void LogisticRegression_train(LogisticRegression*, int*, int*, double);
1615
void LogisticRegression_softmax(LogisticRegression*, double*);
1716
void LogisticRegression_predict(LogisticRegression*, int*, double*);
1817

19-
20-
2118
#endif

c/RBM.c

+238
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <math.h>
4+
#include "RBM.h"
5+
6+
double uniform(double, double);
7+
int binomial(int, double);
8+
double sigmoid(double);
9+
10+
11+
void test_rbm(void);
12+
13+
14+
double uniform(double min, double max) {
15+
return rand() / (RAND_MAX + 1.0) * (max - min) + min;
16+
}
17+
18+
int binomial(int n, double p) {
19+
if(p < 0 || p > 1) return 0;
20+
21+
int i;
22+
int c = 0;
23+
double r;
24+
25+
for(i=0; i<n; i++) {
26+
r = rand() / (RAND_MAX + 1.0);
27+
if (r < p) c++;
28+
}
29+
30+
return c;
31+
}
32+
33+
double sigmoid(double x) {
34+
return 1.0 / (1.0 + exp(-x));
35+
}
36+
37+
38+
void RBM__construct(RBM* this, int N, int n_visible, int n_hidden) {
39+
int i, j;
40+
double a = 1.0 / n_visible;
41+
42+
this->N = N;
43+
this->n_visible = n_visible;
44+
this->n_hidden = n_hidden;
45+
46+
this->W = (double **)malloc(sizeof(double*) * n_hidden);
47+
this->W[0] = (double *)malloc(sizeof(double) * n_visible * n_hidden);
48+
for(i=0; i<n_hidden; i++) this->W[i] = this->W[0] + i * n_visible;
49+
this->hbias = (double *)malloc(sizeof(double) * n_hidden);
50+
this->vbias = (double *)malloc(sizeof(double) * n_visible);
51+
52+
for(i=0; i<n_hidden; i++) {
53+
for(j=0; j<n_visible; j++) {
54+
this->W[i][j] = uniform(-a, a);
55+
}
56+
}
57+
}
58+
59+
void RBM__destruct(RBM* this) {
60+
free(this->W);
61+
free(this->hbias);
62+
free(this->vbias);
63+
}
64+
65+
void RBM_contrastive_divergence(RBM* this, int *input, double lr, int k) {
66+
int i, j, step;
67+
68+
double *ph_mean = (double *)malloc(sizeof(double) * this->n_hidden);
69+
int *ph_sample = (int *)malloc(sizeof(int) * this->n_hidden);
70+
double *nv_means = (double *)malloc(sizeof(double) * this->n_visible);
71+
int *nv_samples = (int *)malloc(sizeof(int) * this->n_visible);
72+
double *nh_means = (double *)malloc(sizeof(double) * this->n_hidden);
73+
int *nh_samples = (int *)malloc(sizeof(int) * this->n_hidden);
74+
75+
/* CD-k */
76+
RBM_sample_h_given_v(this, input, ph_mean, ph_sample);
77+
78+
for(step=0; step<k; step++) {
79+
if(step == 0) {
80+
RBM_gibbs_hvh(this, ph_sample, nv_means, nv_samples, nh_means, nh_samples);
81+
} else {
82+
RBM_gibbs_hvh(this, nh_samples, nv_means, nv_samples, nh_means, nh_samples);
83+
}
84+
}
85+
86+
for(i=0; i<this->n_hidden; i++) {
87+
for(j=0; j<this->n_visible; j++) {
88+
this->W[i][j] += lr * (ph_sample[i] * input[j] - nh_means[i] * nv_samples[j]) / this->N;
89+
}
90+
this->hbias[i] += lr * (ph_sample[i] - nh_means[i]) / this->N;
91+
}
92+
93+
for(i=0; i<this->n_visible; i++) {
94+
this->vbias[i] += lr * (input[i] - nv_samples[i]) / this->N;
95+
}
96+
97+
98+
free(ph_mean);
99+
free(ph_sample);
100+
free(nv_means);
101+
free(nv_samples);
102+
free(nh_means);
103+
free(nh_samples);
104+
}
105+
106+
107+
void RBM_sample_h_given_v(RBM* this, int *v0_sample, double *mean, int *sample) {
108+
int i;
109+
for(i=0; i<this->n_hidden; i++) {
110+
mean[i] = RBM_propup(this, v0_sample, this->W[i], this->hbias[i]);
111+
sample[i] = binomial(1, mean[i]);
112+
}
113+
}
114+
115+
void RBM_sample_v_given_h(RBM* this, int *h0_sample, double *mean, int *sample) {
116+
int i;
117+
for(i=0; i<this->n_visible; i++) {
118+
mean[i] = RBM_propdown(this, h0_sample, i, this->vbias[i]);
119+
sample[i] = binomial(1, mean[i]);
120+
}
121+
}
122+
123+
double RBM_propup(RBM* this, int *v, double *w, double b) {
124+
int j;
125+
double pre_sigmoid_activation = 0.0;
126+
for(j=0; j<this->n_visible; j++) {
127+
pre_sigmoid_activation += w[j] * v[j];
128+
}
129+
pre_sigmoid_activation += b;
130+
return sigmoid(pre_sigmoid_activation);
131+
}
132+
133+
double RBM_propdown(RBM* this, int *h, int i, double b) {
134+
int j;
135+
double pre_sigmoid_activation = 0.0;
136+
137+
for(j=0; j<this->n_hidden; j++) {
138+
pre_sigmoid_activation += this->W[j][i] * h[j];
139+
}
140+
pre_sigmoid_activation += b;
141+
return sigmoid(pre_sigmoid_activation);
142+
}
143+
144+
void RBM_gibbs_hvh(RBM* this, int *h0_sample, double *nv_means, int *nv_samples, \
145+
double *nh_means, int *nh_samples) {
146+
RBM_sample_v_given_h(this, h0_sample, nv_means, nv_samples);
147+
RBM_sample_h_given_v(this, nv_samples, nh_means, nh_samples);
148+
}
149+
150+
void RBM_reconstruct(RBM* this, int *v, double *reconstructed_v) {
151+
int i, j;
152+
double *h = (double *)malloc(sizeof(double) * this->n_hidden);
153+
double pre_sigmoid_activation;
154+
155+
for(i=0; i<this->n_hidden; i++) {
156+
h[i] = RBM_propup(this, v, this->W[i], this->hbias[i]);
157+
}
158+
159+
for(i=0; i<this->n_visible; i++) {
160+
pre_sigmoid_activation = 0.0;
161+
for(j=0; j<this->n_hidden; j++) {
162+
pre_sigmoid_activation += this->W[j][i] * h[j];
163+
}
164+
pre_sigmoid_activation += this->vbias[i];
165+
166+
reconstructed_v[i] = sigmoid(pre_sigmoid_activation);
167+
}
168+
169+
free(h);
170+
}
171+
172+
173+
174+
175+
void test_rbm(void) {
176+
srand(0);
177+
178+
int i, j, epoch;
179+
180+
double learning_rate = 0.1;
181+
int training_epochs = 1000;
182+
int k = 1;
183+
184+
int train_N = 6;
185+
int test_N = 2;
186+
int n_visible = 6;
187+
int n_hidden = 3;
188+
189+
// training data
190+
int train_X[6][6] = {
191+
{1, 1, 1, 0, 0, 0},
192+
{1, 0, 1, 0, 0, 0},
193+
{1, 1, 1, 0, 0, 0},
194+
{0, 0, 1, 1, 1, 0},
195+
{0, 0, 1, 0, 1, 0},
196+
{0, 0, 1, 1, 1, 0}
197+
};
198+
199+
// construct RBM
200+
RBM rbm;
201+
RBM__construct(&rbm, train_N, n_visible, n_hidden);
202+
203+
// train
204+
for(epoch=0; epoch<training_epochs; epoch++) {
205+
for(i=0; i<train_N; i++) {
206+
RBM_contrastive_divergence(&rbm, train_X[i], learning_rate, k);
207+
}
208+
}
209+
210+
211+
// test data
212+
int test_X[2][6] = {
213+
{1, 1, 0, 0, 0, 0},
214+
{0, 0, 0, 1, 1, 0}
215+
};
216+
double reconstructed_X[2][6];
217+
218+
// test
219+
for(i=0; i<test_N; i++) {
220+
RBM_reconstruct(&rbm, test_X[i], reconstructed_X[i]);
221+
for(j=0; j<n_visible; j++) {
222+
printf("%.5f ", reconstructed_X[i][j]);
223+
}
224+
printf("\n");
225+
}
226+
227+
228+
// destruct RBM
229+
RBM__destruct(&rbm);
230+
}
231+
232+
233+
234+
int main(void) {
235+
test_rbm();
236+
237+
return 0;
238+
}

c/RBM.h

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef RBM_H
2+
#define RBM_H
3+
4+
typedef struct {
5+
int N;
6+
int n_visible;
7+
int n_hidden;
8+
double **W;
9+
double *hbias;
10+
double *vbias;
11+
} RBM;
12+
13+
void RBM__construct(RBM*, int, int, int);
14+
void RBM__destruct(RBM*);
15+
void RBM_contrastive_divergence(RBM*, int*, double, int);
16+
void RBM_sample_h_given_v(RBM*, int*, double*, int*);
17+
void RBM_sample_v_given_h(RBM*, int*, double*, int*);
18+
double RBM_propup(RBM*, int*, double*, double);
19+
double RBM_propdown(RBM*, int*, int, double);
20+
void RBM_gibbs_hvh(RBM*, int*, double*, int*, double*, int*);
21+
void RBM_reconstruct(RBM*, int*, double*);
22+
23+
#endif

cpp/RBM.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void RBM::contrastive_divergence(int *input, double lr, int k) {
6565
sample_h_given_v(input, ph_mean, ph_sample);
6666

6767
for(int step=0; step<k; step++) {
68-
if (step == 0) {
68+
if(step == 0) {
6969
gibbs_hvh(ph_sample, nv_means, nv_samples, nh_means, nh_samples);
7070
} else {
7171
gibbs_hvh(nh_samples, nv_means, nv_samples, nh_means, nh_samples);

0 commit comments

Comments
 (0)