Skip to content

Commit d3c497b

Browse files
committed
Add RuCLIP cpp library from DeliriumV01D/RuCLIP
1 parent baecd89 commit d3c497b

19 files changed

Lines changed: 29621 additions & 0 deletions

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ if (BUILD_EXAMPLES)
6161
add_subdirectory(example)
6262
endif(BUILD_EXAMPLES)
6363

64+
65+
option(USE_CLIP "Should be used RuCLIP|CLIP for objects classification?" OFF)
66+
if (USE_CLIP)
67+
add_definitions(-DUSE_CLIP)
68+
endif(USE_CLIP)
69+
6470
option(BUILD_CARS_COUNTING "Should compiled Cars counting example?" OFF)
6571
if (BUILD_CARS_COUNTING)
6672
add_definitions(-DBUILD_CARS_COUNTING)

example/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ if (BUILD_CARS_COUNTING)
5454
add_definitions(-DBUILD_CARS_COUNTING)
5555
endif(BUILD_CARS_COUNTING)
5656

57+
if (USE_CLIP)
58+
add_definitions(-DUSE_CLIP)
59+
set(LIBS ${LIBS} ruclip)
60+
endif(USE_CLIP)
5761

5862
ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCES} ${HEADERS})
5963

thirdparty/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
add_subdirectory(inih)
22
# add_subdirectory(Circular_Code)
3+
4+
if (USE_CLIP)
5+
add_subdirectory(ruclip)
6+
endif(USE_CLIP)

thirdparty/ruclip/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
2+
project(ruclip)
3+
4+
find_package(Torch REQUIRED)
5+
6+
include_directories(${CMAKE_SOURCE_DIR}/youtokentome)
7+
include_directories(${CMAKE_SOURCE_DIR}/youtokentome/third_party)
8+
9+
file(GLOB RUCLIP_SOURCE_FILES *.cpp *.cpp)
10+
file(GLOB RUCLIP_HEADER_FILES *.h* *.h*)
11+
12+
add_library(${PROJECT_NAME} SHARED ${RUCLIP_SOURCE_FILES} ${RUCLIP_HEADER_FILES})
13+
14+
set(RUCLIP_LIBS
15+
${OpenCV_LIBS}
16+
${TORCH_LIBRARIES}
17+
)
18+
19+
20+
target_link_libraries(${PROJECT_NAME} ${RUCLIP_LIBS})
21+
22+
install(TARGETS ${PROJECT_NAME}
23+
EXPORT MTTrackingExports
24+
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
25+
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
26+
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
27+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME})
28+
29+
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "libs")

thirdparty/ruclip/RuCLIP.cpp

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#include "RuCLIP.h"
2+
3+
ResidualAttentionBlockImpl :: ResidualAttentionBlockImpl(const std::string &module_name, const int d_model, const int n_head, const torch::Tensor &attn_mask)
4+
: torch::nn::Module(module_name)
5+
{
6+
Attn = torch::nn::MultiheadAttention(d_model, n_head);
7+
Ln1 = RCLayerNorm(std::vector<int64_t>() = { (int64_t)d_model });
8+
Mlp = torch::nn::Sequential({
9+
{"c_fc", torch::nn::Linear(d_model, d_model * 4)},
10+
{"gelu", QuickGELU()},
11+
{"c_proj", torch::nn::Linear(d_model * 4, d_model)}
12+
});
13+
Ln2 = RCLayerNorm(std::vector<int64_t>() = { (int64_t)d_model });
14+
AttnMask = attn_mask;
15+
16+
register_module("attn", Attn);
17+
register_module("ln_1", Ln1);
18+
register_module("mlp", Mlp);
19+
register_module("ln_2", Ln2);
20+
//register_buffer("attn_mask", AttnMask);
21+
}
22+
23+
torch::Tensor ResidualAttentionBlockImpl :: Attention(const torch::Tensor &x)
24+
{
25+
if (AttnMask.defined() && (AttnMask.numel() != 0))
26+
AttnMask = AttnMask.to(x.dtype()).to(x.device());
27+
/*return Attn(x, x, x, weights = False, attn_mask = self.attn_mask)[0];*/
28+
//std::tuple<Tensor, Tensor> forward(const Tensor & query, const Tensor & key, const Tensor & value, const Tensor & key_padding_mask = {}, bool need_weights = true, const Tensor & attn_mask = {}, bool average_attn_weights = true)
29+
return std::get<0>(Attn->forward(x, x, x, {}, false, AttnMask));
30+
}
31+
32+
torch::Tensor ResidualAttentionBlockImpl :: forward(const torch::Tensor &x)
33+
{
34+
auto result = x + Attention(Ln1(x));
35+
result = result + Mlp->forward(Ln2(result));
36+
return result;
37+
}
38+
39+
40+
41+
TransformerImpl :: TransformerImpl(const std::string &module_name, const int width, const int layers, const int heads, const torch::Tensor &attn_mask /*= torch::Tensor()*/)
42+
: torch::nn::Module(module_name), Width(width), Layers(layers), Heads(heads)/*, AttnMask(attn_mask)*/
43+
{
44+
for (int i = 0; i < layers; i++)
45+
Resblocks->push_back(ResidualAttentionBlock(module_name + "_" + std::to_string(i), width, heads, attn_mask));
46+
47+
register_module("resblocks", Resblocks); //???
48+
//for (int i = 0; i < Resblocks->size(); i++)
49+
// register_module(module_name + "_res_attn_block_" + std::to_string(i), Resblocks[i]);
50+
}
51+
52+
torch::Tensor TransformerImpl :: forward(const torch::Tensor& x)
53+
{
54+
//!!!Сделать проверку и преобразование if (x.type() != )
55+
return Resblocks->forward(x);
56+
}
57+
58+
void TransformerImpl :: InitializeParameters()
59+
{
60+
float proj_std = powf(Width, -0.5f) * pow(2 * Layers, -0.5f);
61+
float attn_std = powf(Width, -0.5f);
62+
float fc_std = powf(2 * Width, -0.5f);
63+
64+
for (int i = 0; i < Resblocks->size(); i++)
65+
{
66+
auto block = Resblocks[i]->as<ResidualAttentionBlock>();
67+
torch::nn::init::normal_(block->GetAttn()->in_proj_weight, 0., attn_std);
68+
torch::nn::init::normal_(block->GetAttn()->out_proj->weight, 0., proj_std);
69+
auto mlp = block->GetMlp();
70+
for (int j = 0; j < mlp->size(); j++)
71+
{
72+
if (mlp[j]->name() == "c_fc")
73+
torch::nn::init::normal_(mlp[j]->as<torch::nn::Linear>()->weight, 0., fc_std);
74+
if (mlp[j]->name() == "c_proj")
75+
torch::nn::init::normal_(mlp[j]->as<torch::nn::Linear>()->weight, 0., proj_std);
76+
}
77+
}
78+
}
79+
80+
81+
82+
VisionTransformerImpl :: VisionTransformerImpl(
83+
const std::string &module_name,
84+
const int input_resolution,
85+
const int patch_size,
86+
const int width,
87+
const int layers,
88+
const int heads,
89+
const int output_dim
90+
) : torch::nn::Module(module_name), InputResolution(input_resolution), OutputDim(output_dim)
91+
{
92+
Conv1 = torch::nn::Conv2d(torch::nn::Conv2dOptions(3, width, patch_size).stride(patch_size).bias(false));
93+
float scale = powf(width, -0.5);
94+
ClassEmbedding = scale * torch::randn(width);
95+
PositionalEmbedding = scale * torch::randn({ (int)pow(input_resolution / patch_size/*деление нацело*/, 2) + 1, width });
96+
LnPre = RCLayerNorm(std::vector<int64_t>() = { (int64_t)width });
97+
VTTransformer = Transformer("visual", width, layers, heads);
98+
LnPost = RCLayerNorm(std::vector<int64_t>() = { (int64_t)width });
99+
Proj = scale * torch::randn({ width, output_dim });
100+
101+
register_buffer("class_embedding", ClassEmbedding);
102+
register_buffer("positional_embedding", PositionalEmbedding);
103+
register_buffer("proj", Proj);
104+
register_module("conv1", Conv1);
105+
register_module("ln_pre", LnPre);
106+
register_module("ln_post", LnPost);
107+
register_module("transformer", VTTransformer);
108+
}
109+
110+
torch::Tensor VisionTransformerImpl :: forward(const torch::Tensor &x)
111+
{
112+
//!!!Сделать проверку и преобразование if (x.type() != )
113+
auto res = Conv1(x); //shape = [*, width, grid, grid]
114+
res = res.reshape({ res.sizes()[0], res.sizes()[1], -1 }); //shape = [*, width, grid **2]
115+
res = res.permute({ 0, 2, 1 }); //shape = [*, grid **2, width]
116+
res = torch::cat({
117+
ClassEmbedding.to(res.dtype()) + torch::zeros({res.sizes()[0], 1, res.sizes().back()}, res.dtype()).to(x.device()),
118+
res
119+
}, 1); //shape = [*, grid **2 + 1, width]
120+
res = res + PositionalEmbedding.to(res.dtype());
121+
res = LnPre(res);
122+
res = res.permute({ 1, 0, 2 }); // NLD->LND
123+
res = VTTransformer(res);
124+
res = res.permute({ 1, 0, 2 }); // LND->NLD
125+
res = LnPost(res.index({ torch::indexing::Slice(), 0, torch::indexing::Slice() }));
126+
if (Proj.defined() && Proj.numel() != 0)
127+
res = torch::mm(res, Proj);
128+
return res;
129+
}
130+
131+
132+
133+
CLIPImpl :: CLIPImpl(
134+
const std::string &module_name,
135+
const int embed_dim,
136+
const int image_resolution,
137+
const int vision_layers,
138+
const int vision_width,
139+
const int vision_patch_size,
140+
const int context_length,
141+
const int vocab_size,
142+
const int transformer_width,
143+
const int transformer_heads,
144+
const int transformer_layers,
145+
const int eos_id /*= 3*/
146+
) : torch::nn::Module(module_name), EosId(eos_id), ContextLength(context_length), VocabSize(vocab_size), TransformerWidth(transformer_width), TransformerLayers(transformer_layers)
147+
{
148+
int vision_heads = vision_width / 64;
149+
Visual = VisionTransformer("visual", image_resolution, vision_patch_size, vision_width, vision_layers, vision_heads, embed_dim);
150+
NVTransformer = Transformer("transformer", transformer_width, transformer_layers, transformer_heads, BuildAttentionMask());
151+
152+
TokenEmbedding = torch::nn::Embedding(vocab_size, transformer_width);
153+
PositionalEmbedding = torch::empty({ context_length, transformer_width }); //!!!type, device
154+
155+
std::cout << "transformer_width: " << transformer_width<< std::endl;
156+
157+
LnFinal = RCLayerNorm(std::vector<int64_t>() = { (int64_t)transformer_width });
158+
TextProjection = torch::empty({ transformer_width, embed_dim }); //!!!type, device
159+
LogitScale = torch::ones({}) * logf(1.f / 0.07f);
160+
161+
register_module("visual", Visual);
162+
register_module("transformer", NVTransformer);
163+
register_module("token_embedding", TokenEmbedding);
164+
register_module("ln_final", LnFinal);
165+
register_buffer("positional_embedding", PositionalEmbedding);
166+
register_buffer("text_projection", TextProjection);
167+
register_buffer("logit_scale", LogitScale);
168+
169+
InitializeParameters();
170+
}
171+
172+
void CLIPImpl :: InitializeParameters()
173+
{
174+
torch::nn::init::normal_(TokenEmbedding->weight, 0., 0.02);
175+
torch::nn::init::normal_(PositionalEmbedding, 0., 0.01);
176+
NVTransformer->InitializeParameters();
177+
if (TextProjection.defined() && TextProjection.numel() != 0)
178+
torch::nn::init::normal_(TextProjection, 0., pow(TransformerWidth, -0.5));
179+
}
180+
181+
torch::Tensor CLIPImpl :: BuildAttentionMask()
182+
{
183+
auto mask = torch::empty({ ContextLength, ContextLength });
184+
mask.fill_(-std::numeric_limits<float>::infinity());
185+
mask.triu_(1);
186+
return mask;
187+
}
188+
189+
///pixel_values : torch::Tensor Processed images from RuCLIPProcessor class, out: image_latents : torch::Tensor Image embeddings
190+
torch::Tensor CLIPImpl :: EncodeImage(torch::Tensor pixel_values)
191+
{
192+
return Visual(pixel_values);
193+
}
194+
195+
///input_ids : torch::Tensor Tokenized texts from RuCLIPProcessor class, out: text_latents : torch::Tensor Text embeddings
196+
torch::Tensor CLIPImpl :: EncodeText(torch::Tensor input_ids)
197+
{
198+
auto x = TokenEmbedding(input_ids); //.type(dtype()) // [batch_size, n_ctx, d_model]
199+
x = x + PositionalEmbedding; //.type(dtype())
200+
x = x.permute({ 1, 0, 2 }); //NLD->LND
201+
x = NVTransformer(x);
202+
x = x.permute({ 1, 0, 2 }); //LND->NLD
203+
x = LnFinal(x); // type(self.dtype) //x.shape = [batch_size, n_ctx, transformer.width]
204+
x = torch::mm(x.index({ torch::arange(x.sizes()[0]), torch::where(input_ids == EosId)[1] }), TextProjection);
205+
return x;
206+
}
207+
208+
torch::Tensor CLIPImpl :: forward(torch::Tensor input_ids, torch::Tensor pixel_values)
209+
{
210+
auto image_features = EncodeImage(pixel_values);
211+
auto text_features = EncodeText(input_ids);
212+
213+
//normalize features
214+
image_features = image_features / image_features.norm(2/*L2*/, -1, true);
215+
text_features = text_features / text_features.norm(2/*L2*/, -1, true);
216+
217+
//cosine similarity as logits
218+
auto scale = LogitScale.exp();
219+
auto logits_per_image = scale * torch::mm(image_features, text_features.t());
220+
auto logits_per_text = logits_per_image.t();
221+
222+
return logits_per_image;
223+
}

0 commit comments

Comments
 (0)